function Slideshow(obj, registered_id, configs) {
  this.default_configs = {
    'transition_speed' : 1500,
    'slide_duration' : 7000
  };

  this.constructor = function(obj, registered_id, configs) {
    this.slideshow_obj = obj;
    this.registered_id = registered_id;

    this.setup_configs(configs);
    this.setup_slides();
    this.add_advancers();

    if (this.auto_play) {
      this.begin();
    }
  }
  
  this.setup_configs = function(configs) {
    this.configs = typeof(configs) != 'undefined' ? configs : {};
    for (var i in this.default_configs) {
      this.configs[i] = typeof(configs[i]) == 'undefined' ? this.default_configs[i] : configs[i];
    }

    this.auto_advance = typeof(this.configs['auto_advance']) != 'undefined' ? this.configs['auto_advance'] : true;
    this.auto_play = typeof(this.configs['auto_play']) != 'undefined' ? this.configs['auto_play'] : true;
  }
  
  this.setup_slides = function() {
    this.slide_list = $(this.slideshow_obj).children('li');
    this.slide_list.addClass('slide');
    for (var i=1; i < this.slide_list.length; i++) {
      $(this.slide_list[i]).hide();
    };
  }

  this.add_advancers = function() {
    innerHTML = '';
    for (var i=0; i < this.slide_list.length; i++) {
      innerHTML += '<a href="javascript:' + this.configs['slideshow_manager_name'] + '.slideshow(' + this.registered_id + ').goto_slide(' + i + ', true)"><span>' + (i + 1) + '</span></a>';
    };
    $(this.slideshow_obj).append('<li class="advancers">' + innerHTML + '</li>');
    this.advancer_list = $(this.slideshow_obj).find('li.advancers a');
  }

  this.begin = function() {
    this.current_slide_index = 0
    $(this.slide_list[this.current_slide_index]).show();
    $(this.advancer_list[this.current_slide_index]).addClass('active');
    if (this.auto_advance) {
      this.schedule_slide();
    }
  }

  this.goto_slide = function(i, pause_playback) {
    this.cancel_scheduled_slide();
    this.hide_current_slide();
    $(this.slide_list[i]).fadeIn(this.configs['transition_speed']);
    $(this.advancer_list[i]).addClass('active');
    this.current_slide_index = i;
    if (this.auto_advance && ! pause_playback) {
      this.schedule_slide();
    }
  }

  this.next = function() {
    this.hide_current_slide();
    this.goto_slide(this.index_after(this.current_slide_index));
  }

  this.hide_current_slide = function() {
    $(this.slide_list[this.current_slide_index]).fadeOut(this.configs['transition_speed']);
    $(this.advancer_list[this.current_slide_index]).removeClass('active');
  }
  
  this.schedule_slide = function() {
    eval_str = this.configs['slideshow_manager_name'] + '.slideshow(' + this.registered_id + ').next()';
    this.timeout_id = setTimeout(eval_str, this.configs['slide_duration']);
  }
  
  this.cancel_scheduled_slide = function() {
    clearTimeout(this.timeout_id);
  }
  
  this.index_after = function(i) { return (i + 1) % this.slide_list.length; }
  this.index_before = function(i) { return (i + (this.slide_list.length - 1)) % this.slide_list.length; }

  this.constructor(obj, registered_id, configs);
}

function SlideshowManager() {

  this.slideshow_list = [];
  this.slideshow_ids = [];

  this.add_slideshow = function(obj_id, configs) {
    if (slideshow_obj = document.getElementById(obj_id)) {
      this.slideshow_ids[obj_id] = this.slideshow_list.length;
      this.slideshow_list[this.slideshow_list.length] = new Slideshow(slideshow_obj, this.slideshow_list.length, configs);
    }
  }

  this.slideshow = function(slideshow_id) {
    if (typeof(slideshow_id) == 'string') {
      slideshow_id = this.slideshow_ids[slideshow_id]
    };
    return this.slideshow_list[slideshow_id];
  }

}

function begin_slideshow(obj_id, configs) {
  if (typeof(_IMG_SLIDESHOW_MANAGER) == 'undefined') {
    _IMG_SLIDESHOW_MANAGER = new SlideshowManager();
  }
  configs = typeof(configs) != 'undefined' ? configs : {};
  configs['slideshow_manager_name'] = '_IMG_SLIDESHOW_MANAGER';
  _IMG_SLIDESHOW_MANAGER.add_slideshow(obj_id, configs);
}

