/*  S7, version 0.0.2
 *  (c) 2008 FIXME full name
 *
 *  S7 is freely distributable under
 *  the terms of an MIT-style license.
 *  For details, see the web site: http://NOTE-ENTER-URL.com
 *
 *--------------------------------------------------------------------------*/

var S7 = {
  version: '0.0.2',
};

S7.utils = {};

S7.utils.extend = function(subc, superc) {
  var F = function() {};
  F.prototype = superc.prototype;
  subc.prototype = new F();
  subc.prototype.constructor = subc;
  subc.prototype.superclass = superc.prototype;
};
(function() {

S7.SlideShow = function(context) {
  this.slides = [];
  this.callbacks = [];
};

S7.SlideShow.prototype.addSlide = function(id, element) {
  this.slides.push( new S7.Slide(id, element) );
};

S7.SlideShow.prototype.goTo = function(idOrIndexOrSlide) {
  var slide = idOrIndexOrSlide && typeof idOrIndexOrSlide == 'object' ? idOrIndexOrSlide : this.getSlide(idOrIndexOrSlide);
  var index;
  if (slide && this.currentSlide != slide) {
    if (this.currentSlide) {
      this.currentSlide.hide();
      index = this.getIndex(this.currentSlide);
      triggerCallbacks.call(this, 'slide.hidden', this.currentSlide, index);
    }
    slide.show();
    index = this.getIndex(slide);
    triggerCallbacks.call(this, 'slide.shown', slide, index);
    this.currentSlide = slide;
  }
};

S7.SlideShow.prototype.getSlide = function(idOrIndex) {
  var slide = null;
  var index = 0;
  if (typeof idOrIndex == 'number') {
    if (idOrIndex >= 0 && idOrIndex < this.slides.length) {
      slide = this.slides[idOrIndex];
    }
  }
  else {
    while (!slide && index < this.slides.length) {
      if (this.slides[index].id == idOrIndex) {
        slide = this.slides[index];
      }
      index += 1;
    }
  }
  return slide;
};

S7.SlideShow.prototype.goNext = function(delta) {
  var dest = this.getNext(delta);
  if (dest) {
    this.goTo(dest);
  }
};

S7.SlideShow.prototype.goPrev = function() {
  this.goNext(-1);
};

S7.SlideShow.prototype.getNext = function(delta) {
  delta = delta || 1;
  var index = 0;
  var nextIndex;
  while (index < this.slides.length) {
    if (this.slides[index] == this.currentSlide) {
      nextIndex = index + delta;
      if (nextIndex >= 0 && nextIndex < this.slides.length) {
        return this.slides[nextIndex];
      }
      else {
        return null;
      }
    }
    index += 1;
  }
};

S7.SlideShow.prototype.getPrevious = function() {
  return this.getNext(-1);
};

S7.SlideShow.prototype.registerCallback = function(fn) {
  this.callbacks.push(fn);
};

S7.SlideShow.prototype.getIndex = function(slide) {
  for (var i = 0; i < this.slides.length; i += 1) {
    if (slide == this.slides[i]) {
      return i;
    }
  }
};

S7.SlideShow.prototype.start = function() {
  this.goTo(0);
};


S7.Slide = function(id, element) {
  this.id = id;
  this.element = element;
};

S7.Slide.prototype.show = function() {
  this.element.style.display = 'block';
  this.element.className += ' currentSlide';
};


S7.Slide.prototype.hide = function() {
  this.element.style.display = 'none';
  this.element.className = this.element.className.replace(' currentSlide', '');
};

var triggerCallbacks = function() {
  for (var i = 0; i < this.callbacks.length; i += 1) {
    this.callbacks[i].apply(this, arguments);
  }
};

})();
(function() {

S7.S5 = function() {
  this.superclass.constructor.call(this);
  var allDivs = document.getElementsByTagName('div');
  for (var i = 0, j = 0, div; i < allDivs.length; i += 1) {
    div = allDivs[i];
    if (div.className.search(/(^|\s)slide(\s|$)/) != -1) {
      div.id = div.id || 'slide-' + j;
      div.style.display = 'none';
      this.addSlide(div.id, div);
      j += 1;
    }
  }
  initControls.call(this);
  this.start();
};

S7.utils.extend(S7.S5, S7.SlideShow);


function initControls() {
  var controls = getOrCreate('controls');
  var currentSlide = getOrCreate('current-slide', controls);
  currentSlide.innerHTML = "0/" + (this.slides.length - 1);
  var form = getOrCreate('control-form', controls, false, 'form');
  var select = getOrCreate('jumplist', form, false, 'select');
  while (select.firstChild) {
    select.removeChild(select.firstChild);
  }
  var i, slide, title;
  for (i = 0; i < this.slides.length; i += 1) {
    slide = this.slides[i];
    title = slide.element.getElementsByTagName('h1')[0].innerHTML.replace(/<[^>]*>/g, '');
    select.appendChild(new Option(i + ': ' + title));
  }
  select.addEventListener('change', function(ss) {
    return function(e) {
      ss.goTo(this.selectedIndex);
    };
  }(this), false);

  this.registerCallback(function(type, slide, index) {
    if (type == 'slide.shown') {
      select.selectedIndex = index;
    }
  });

  this.registerCallback(function(type, slide, index) {
    if (type == 'slide.shown') {
      currentSlide.innerHTML = index + "/" + (this.slides.length - 1);
    }
  });

  document.addEventListener('keyup', getKeyupHandler(this), false);
  document.addEventListener('click', getClickHandler(this), false);
}

function isSelfOrDescendant(el, id) {
  var p = el;
  do {
    if (p.id == id) return true;
  } while (p = p.parentNode);
}

function getKeyupHandler(ss) {
  return function(e) {
    if (isSelfOrDescendant(e.target, 'controls')) return;
    switch (e.keyCode) {
      case 39: // right
      case 40: // down
      case 32: // spacebar
        ss.goNext();
        break;
      case 37: // left
      case 38: // up
        ss.goPrev();
        break;
    }
  };
}

function getClickHandler(ss) {
  return function(e) {
    if (e.target.tagName.toLowerCase() == 'a' || isSelfOrDescendant(e.target, 'controls')) {
      return;
    }
    ss.goNext();
  };
};


function getOrCreate(id, parent, prepend, tag) {
  prepend = prepend || false;
  parent = parent || document.body;
  tag = tag || 'div';
  var el = document.getElementById(id);
  if (!el) {
    el = document.createElement(tag);
    el.id = id;
    if (prepend) {
      parent.insertBefore(el, parent.firstChild);
    }
    else {
      parent.appendChild(el);
    }
  }
  return el;
}

})();
