/*
 * Author : Romuald du Song
 * Based on ideas from GreyWyvern http://www.greywyvern.com
 * Dependency : prototype.js 1.3.1 http://prototype.conio.net
 *
 * Usage :
 * 
 *  var scroller = new CssScroller(content_id, container_id, options);
 *  scroller.scroll();
 *
 *  Content_id should contain div nodes that will be scrolled in the container view.
 *
 * Tested on Firefox 1.0.4 (Win|Linux) / IE 6.0 (Win)
 * Version 1.0
 * Copyright 2005 e-Fininfo
 */

Object.extend(Element, {
  getWidth: function(element) {
    element = $(element);
    return element.offsetWidth; 
  }
});

var CssScroller = Class.create();
CssScroller.prototype = {
  initialize: function(element, container, options) {
  	this.element = $(element);
  	this.container = $(container);
	this.setOptions(options);
	var direction = this.options.direction;
	this.slide = ((direction == "up" || direction == "down") ? this.options.height : this.options.width) / this.options.begin;
	this._cleanContainer();
	this._attachBehaviors();
	this.pos = 0;
  },

  setOptions: function(options) {
     this.options = {
	    width       : Element.getWidth(this.container),
	    height      : Element.getHeight(this.container),
	    speed	: 20,  /* en milli-secondes */
	    pause	: 3000, /* en milli-secondes */
	    decel	: 1.2, /* >=  1 */
	    begin	: 8,
	    direction	: "up"
	    };
	   Object.extend(this.options, options || {});
    },

  scroll: function() {
    this.container.style.overflow = "hidden";

    for (var i = 0; i < this.tabs.length; i++) {
	    var div = this.tabs[i];
	    div.style.position = "relative";
	    if (this.options.direction == "up" || this.options.direction == "down") {
		    div.style.left = "0px";
		    div.style.top =  "0px";
	    } else {
		    div.style.left = (i == 0) ? "0px" : ((this.options.direction == "left") ? "" : "-") + this.options.width + "px";
		    div.style.top = "0px";
	    } 
    } 

    this.container.appendChild(this.tabs[this.pos]);
    var next = this.pos + 1;
    if (next >= this.tabs.length) next = 0;
    this.container.appendChild(this.tabs[next]);
    this._startPosition(this.tabs[next], this.tabs[this.pos]);

    setTimeout((function() {this.scrollLoop()}).bind(this), this.options.pause);
  },

  _startPosition: function(element, previous) {
	    if (this.options.direction == "down") {
		    element.style.left = "0px";
		    var gap = this.options.height + this._scrollHeight(previous);
		    element.style.top = - gap + "px";
	    } else if (this.options.direction == "up") {
		    element.style.left = "0px";
		    var gap = this.options.height - this._scrollHeight(previous);
		    if (gap < 0) gap = 0;
		    element.style.top =  gap + "px";
	    } else {
		    element.style.left = ((this.options.direction == "left") ? "" : "-") + this.options.width + "px";
		    element.style.top = "-" + this._scrollHeight(previous) + "px";
	    } 
  },

  _scrollHeight: function(element) {
    var a = element.scrollHeight;
    var b = element.offsetHeight;
    return (a > b) ? a : b;
  },

  scrollLoop: function() {
    this.slide = Math.max(this.slide / this.options.decel, 1);
    var slideInc = (this.options.direction == "up" || this.options.direction == "left") ? -parseInt(this.slide) : parseInt(this.slide);
    var div = this.tabs[this.pos];
    var next = this.pos + 1;
    if (next >= this.tabs.length) next = 0;
    var nextDiv = this.tabs[next];
    var limiteH = this._scrollHeight(div);

  if ((this.options.direction == "up" && 
  	Math.max(parseInt(div.style.top) + slideInc, parseInt(nextDiv.style.top) + slideInc) <= -limiteH) ||
      (this.options.direction == "down" && 
      	Math.min(parseInt(div.style.top) + slideInc, parseInt(nextDiv.style.top) + slideInc) >= -limiteH) ||
      (this.options.direction == "left" && 
      	Math.max(parseInt(div.style.left) + slideInc, parseInt(nextDiv.style.left) + slideInc) <= 0) ||
      (this.options.direction == "right" && 
      	Math.min(parseInt(div.style.left) + slideInc, parseInt(nextDiv.style.left) + slideInc) >= 0)) {
            /* alert("div:"+(parseInt(div.style.left) + slideInc)+" next:"+(parseInt(nextDiv.style.left) + slideInc)); */
	    this.slide = ((this.options.direction == "up" || this.options.direction == "down") ? this.options.height : this.options.width) / this.options.begin;

	    this.container.removeChild(div);

	    this.pos = next;
	    if (++next >= this.tabs.length) next = 0;

	    div = this.tabs[this.pos];
	    nextDiv = this.tabs[next];
	    this.container.appendChild(nextDiv);

	    div.style.top = "0px";
	    div.style.left = "0px";
    	    this._startPosition(nextDiv, div);
	    setTimeout((function() {this.scrollLoop()}).bind(this), this.options.pause);
    } else {
	    this._scrollElement(div, slideInc);
	    this._scrollElement(nextDiv, slideInc);
	    setTimeout((function() {this.scrollLoop()}).bind(this), this.options.speed);
    }
  },

  _scrollElement: function(element, step) {
      if (this.options.direction == "up" || this.options.direction == "down") {
	      element.style.top = (parseInt(element.style.top) + step) + "px";
      } else {
	      element.style.left = (parseInt(element.style.left) + step) + "px";
      }
  },

  _attachBehaviors: function() {
	var childs = this._getDirectChildrenByTag(this.element, 'DIV');
	this.tabs = new Array();
	for( var i = 0 ; i < childs.length ; i++ ){
		var node = childs[i].cloneNode(true);
		this.tabs.push(node);
	}
	if (childs.length == 1) {
		this.tabs.push(childs[0].cloneNode(true));
	}
  },

  _cleanContainer: function() {
  	var childs = this.container.childNodes;
	for( var i = 0 ; i < childs.length ; i++ ){
		this.container.removeChild(childs[i]);
	}
  },

  _getDirectChildrenByTag: function(e, tagName) {
	var kids = new Array();
	var allKids = e.childNodes;
	for( var i = 0 ; i < allKids.length ; i++ )
		 if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
			 kids.push(allKids[i]);
	return kids;
  }
};

