#include "config.h"

#include "options.hpp"

#ifdef c_movie
#include "movie.hpp"
#endif

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

#ifdef c_picture
#include "pictures.hpp"
#endif

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

#include "gettext.hpp"
#include "shutdown.hpp"

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

Options::Options()
{
  input_master = Input_master::get_instance();
  themes = Themes::get_instance();
  render = Render::get_instance();
  conf = Config::get_instance();
  go = GlobalOptions::get_instance();
}

bool Options::mainloop() 
{
  input_map *old_map = input_master->cur_map;
  input_master->cur_map = &input_master->standard;

  Shutdown &sd = Shutdown::get_instance();
  
  bool reload = false;

  Input input;

  vector<Option*>::iterator iter = val.begin();
  int pos = 0; // position in values, used by print()

  // set the element to the first non-type element
  do {
    vector<Option*>::iterator j = val.end(); --j;
    if (iter != j) {
      ++iter; ++pos;
    } else {
      iter = val.begin(); pos = 0;
    }
  } while ((*iter)->type);

  bool reload_all = false;
  int sort_pos = 0;

  bool update_needed = true;

  while (!(input.command == "back" && input.mode == "general"))
    {
      if (update_needed)
	print((*iter)->name, pos);
      
      input = input_master->device->get_input();
      
      if (sd.is_enabled()) {
      	sd.cancel();
      	continue;
      }

      update_needed = true;

      if (input.command == "prev")
 	{
	  do {
	    if (iter != val.begin()) {
	      --iter; --pos;
	    } else {
	      vector<Option*>::iterator j = val.end(); --j;
	      iter = j; pos = val.size() - 1;
	    }
	  } while ((*iter)->type);
 	}
      else if (input.command == "next")
 	{
	  do {
	    vector<Option*>::iterator j = val.end(); --j;
	    if (iter != j) {
	      ++iter; ++pos;
	    } else {
	      iter = val.begin(); pos = 0;
	    }
	  } while ((*iter)->type);
 	}
      else if (((*iter)->name == gettext("reload")) &&
	       (input.command == "left" || input.command == "right" || input.command == "action"))
	{
	  read_dirs();
	  reload = true;
	}
      else if (input.command == "left" || input.command == "right") 
	{

	  if (((*iter)->name == gettext("sorting")) &&
	      (input.command == "left" || input.command == "right"))
	    if (!reload_all) {
	      sort_pos = (*iter)->pos;
	      reload_all = true;
	    } 

	  if (input.command == "left") {
	    if ((*iter)->pos != 0) {
	      --(*iter)->pos;
	    } else {
	      (*iter)->pos = (*iter)->values.size() - 1;
	    }
	  }
	  else if (input.command == "right") {
	    if ((*iter)->pos != ((*iter)->values.size() - 1)) {
	      ++(*iter)->pos;
	    } else {
	      (*iter)->pos = 0;
	    }
	  }

	  if (sort_pos == (*iter)->pos)
	    reload_all = false;
	}
      else
	update_needed = !general_loop_check(input);
    }

  input_master->cur_map = old_map;

  if (reload_all) {
#ifdef c_music
    Audio *audio = Audio::get_instance();
    audio->load_current_dirs();
#endif
#ifdef c_movie
    Movie &movie = Movie::get_instance();
    movie.load_current_dirs();
#endif
#ifdef c_picture
    Pictures &pic = Pictures::get_instance();
    pic.load_current_dirs();
#endif

    return true;
  } else
    return reload;
}

void Options::print_element(const string& element, const string& value,
			    bool marked, int x, int y, int max_size, int max_element_size)
{
  if (marked) {
    render->current.add(new PObj(themes->options_marked_left, x-50, y, 1, NOSCALING));
    render->current.add(new PObj(themes->options_marked, x-25, y, 90+max_size, 1));
    render->current.add(new PObj(themes->options_marked_right, x-25+90+max_size, y, 1, NOSCALING));
  }
  
  render->current.add(new TObj(element, "Vera/17", x, y, themes->options_font1, 
			       themes->options_font2, themes->options_font3, 2));
  render->current.add(new TObj(value, "Vera/17", x + max_element_size + 50, y,
			       themes->options_font1, themes->options_font2, 
			       themes->options_font3, 2));
}

void Options::print(const string& marking, int pos)
{
  render->prepare_new_image();

  render->current.add(new PObj(themes->options_background, 0, 0, 0, SCALE_FULL));
  
  render->current.add(new PObj(themes->startmenu_options, 25, 10, 2, NOSCALING));
 
  if (themes->show_header) {
    render->current.add(new TObj(header, "Vera/28", 100, 10,
				 themes->options_header_font1, themes->options_header_font2, 
				 themes->options_header_font3, 2));
  }

  int y = (conf->p_v_res()>800)?105:70;

  bool direction_down = true;
  int space = vector_lookup(val, pos)->type ? 50 : 25;
  int max_space = conf->p_h_res()-(2*y);
  int divert_pos_down = 0, divert_pos_up = 0;
  int cur_pos = 0, nr_elements = 0;
  bool direction_up_ok = true, direction_down_ok = true;

  if (header != gettext("Options"))
    y += 50;

  while (true) {
    if (!direction_down) {
      cur_pos = pos + divert_pos_up + 1;
      if (cur_pos <= val.size() - 1) {
	space += vector_lookup(val, cur_pos)->type ? 50 : 25;
	if (space > max_space)
	  break;
	nr_elements += 1;
	divert_pos_up += 1;
      } else
	direction_up_ok = false;

      direction_down = true;
    } else {
      cur_pos = pos - divert_pos_down - 1;
      if (cur_pos >= 0) {
	space += vector_lookup(val, cur_pos)->type ? 50 : 25;
	if (space > max_space)
	  break;
	nr_elements += 1;
	divert_pos_down += 1;
      } else
	direction_down_ok = false;

      direction_down = false;
    }

    if (!direction_up_ok && !direction_down_ok)
      break;
  }

  int max_element = 0, max_value = 0;

  // calculate size
  for (std::vector<Option*>::const_iterator i = val.begin(), 
	 end = val.end(); i != end; ++i) {

    Option *o = *i;

    if (o->name != gettext("reload") && !o->type) {

      int element_size, value_size, y_size;
      string_format::calculate_string_size(o->name, "Vera/17", &element_size, &y_size);

      for (vector<string>::const_iterator oval = o->values.begin(), 
	     oend = o->values.end(); oval != oend; ++oval) {
	string_format::calculate_string_size(*oval, "Vera/17", &value_size, &y_size);
	max_value = std::max(value_size, max_value);
      }

      max_element = std::max(element_size, max_element);
    } else if (o->name == gettext("reload")) {
      int element_size, y_size;
      string_format::calculate_string_size(o->name, "Vera/17", &element_size, &y_size);
      max_element = std::max(element_size, max_element);
    }
  }

  if (max_element > conf->p_v_res()/2 - 20)
    max_element = conf->p_v_res()/2 - 20;
  
  if (max_value > conf->p_v_res()/2 - 20)
    max_value = conf->p_v_res()/2 - 20;

  int max = max_element + max_value;

  if (max == 0)
    max = 70;

  int x = (conf->p_v_res()-max)/2;

  if (header != gettext("Options"))
    print_element(gettext("reload"), "", (gettext("reload") == marking), x, y-50, max, max_element);
  
  int startpos = pos - divert_pos_down;
  
  for (int i = startpos, end = val.size(); i < end; ++i) {

    if (i - startpos > nr_elements)
      break;

    Option *o = vector_lookup(val, i);

    if (o->type) {

      y += 10;
      render->current.add(new TObj(o->name, "Vera/20", x-25, y,
				   themes->options_font1, themes->options_font2, 
				   themes->options_font3, 1));
      y += 40;

    } else if (o->name != gettext("reload")) {

      string name = o->name;
      string_format::format_to_size(name, "Vera/17", max_element, false);
      string value = vector_lookup(o->values, o->pos);
      string_format::format_to_size(value, "Vera/17", max_value, false);

      print_element(name, value, o->name == marking, x, y, max, max_element);
      y += 25;
    }
  }

  render->draw("options");

  render->image_mut.leaveMutex();
}
