/**
 * @author Bjørge Næss
 * @copyright Bjørge Næss (c) 2008
 * @requires Prototype
 * @requires UrlHashWriter
 * @requires Scriptaculous
 */
var Slider = Class.create({

	initialize: function(element, options) {

		element = $(element);

		this.options = {
			previousButton: null,
			nextButton: null,
			playButton: null,
			autoplay: false,
			loop: false,
			counter: null
		};

		Object.extend(this.options, options || { });

		if (element.tagName.toLowerCase() == 'ul') {
			// Then, create the wrapper
			this.element=new Element('div', {'class': 'slider'});
			// and wrap the ul
			element.wrap(this.element);
			this.ulEl = element;
            if (!this.element.id) this.element.identify();
			this.element.id = element.id+'_wrp';
		}
		else {
			this.element = element;
			this.element.addClassName('slider');
			this.ulEl = this.element.down('ul');
			if (!this.ulEl) return alert('No UL element contained in given element: '+element.id);
		}

		this.options.counter = $(this.options.counter);

		this.options.previousButton = $(this.options.previousButton);
        this.options.nextButton = $(this.options.nextButton);
		if (this.options.previousButton) this.options.previousButton.observe('click', this.previous.bind(this));
		if (this.options.nextButton) this.options.nextButton.observe('click', this.next.bind(this));

		if (this.options.playButton) {
			this.options.playButton = $(this.options.playButton);
            var lbl = this.options.autoplay ? 'pause' : 'play';
			this.options.playButton.addClassName(lbl);
			this.options.playButton.observe('click', this.playpause.bind(this));
		}
		this.firstElement = this.ulEl.down('li');

		this.lastElement = this.firstElement.siblings().last();

		this.currentElement = null;

		this.ulEl.observe('click', this.centerOnClick.bindAsEventListener(this));

		Event.observe(document, 'keydown', function(e) {
			if (e.keyCode == Event.KEY_RIGHT) this.next();
			if (e.keyCode == Event.KEY_LEFT) this.previous();
		}.bind(this));

		//Event.observe(this.options.previewer, 'click', this.next.bind(this))

		Event.observe(window, 'load', this.startUp.bind(this));
	},
	startUp: function() {
		this.viewport = this.element.getDimensions();
		this.alignMiddle();
		this._hashChangeCheck();
		if (!this.currentElement) this.first();
		setInterval(this._hashChangeCheck.bind(this), 200);
		this.updateButtonsStyle();
        if (this.options.autoplay)
            this.playpause(true);
   	},
	centerOnClick: function(event) {
		var liEl = event.findElement('li');
        if (!liEl) return;
		this.moveTo(liEl);
		Event.stop(event);
	},
	moveTo: function(liEl) {

		// Fix for IE7
		this.viewport = this.element.getDimensions();

		var current = this.element.down('.current');
		if (current) current.removeClassName('current');

		if (!this.viewport.width || this.getWidth() <= this.viewport.width) return this.setCurrent(liEl);

		var it = this.firstElement;
		var element_left = 0;
		while (it && it != liEl) {
			element_left += it.getWidth();
			it = it.next('li');
		}

        // Remaining space on right side of element to move to
		var remaining = this.getWidth() - element_left;

        // Center position of element to move to
		var element_center = liEl.getWidth() / 2;
        // Viewport center
		var viewport_center = this.viewport.width / 2;

        // Calculate new position
		var new_pos = element_left*-1 + (viewport_center - element_center);

		if (new_pos > 0) new_pos = 0;

		//console.log((viewport_center - liEl.getWidth()) + remaining <= this.viewport.width)
		if ((viewport_center - element_center) + remaining <= this.viewport.width) {
			new_pos = (this.getWidth() - this.viewport.width)*-1;
		}

		if (this.getLeft() != new_pos) new Effect.Move(this.ulEl, {
			x: new_pos, y: 0, mode: 'absolute',
			transition: Effect.Transitions.sinoidal
		});
         /**/
		this.setCurrent(liEl);
	},
	setCurrent: function(liEl) {
		liEl.addClassName('current');
        this.currentElement = liEl;
        var sibs = this.ulEl.select('li');
        for (var offset = 0; offset < sibs.length; offset++) {
            if (sibs[offset] == liEl) {
		        UrlHashWriter.setVariable('slider_'+this.element.id, offset);
                break;
            }
        }
        if (this.options.counter) {
            offset++;
			var total = offset + liEl.nextSiblings().length;
			this.options.counter.update(offset+' / '+total);
		}
        clearTimeout(this.shiftTimer);
        if (this.options.autoplay) this.playpause(true);
        this.updateButtonsStyle();
	},
    playpause: function(bool) {
		if (bool !== true && bool !== false) bool = !this.options.autoplay;

		if (this.options.playButton) {
            this.options.playButton.removeClassName('play');
            this.options.playButton.removeClassName('pause');
            this.options.playButton.addClassName(bool ? 'pause' : 'play');
            this.options.playButton.addClassName(bool ? 'pause' : 'play');
        }

		if (bool && !this.options.autoplay) this.next();
        this.options.autoplay = bool;
		if (bool) this.shiftTimer = setTimeout(this.next.bind(this), 5000);
		else clearTimeout(this.shiftTimer);
	},
	getWidth: function() {
		var list = this.ulEl.select('li');
		var width = 0;
		for (var i = 0; i < list.length; i++) {
			width += Element.getWidth(list[i]);
		}
		return width;
	},
	setLeft: function(left) {
		this.ulEl.style.left=left+'px';
	},
	getLeft: function() {
		return parseFloat(this.ulEl.style.left) || 0;
	},
	getCenterElement: function() {
		var center = this.viewport.width / 2;

		var list = this.ulEl.select('li');

		var left = this.getLeft();

		//console.log(left)
		var element;

		for (var i = 0; i < list.length; i++) {
			element = list[i];
			left += element.getWidth();
			if (left >= center) break;
		}

		return element;
	},
	getNextOutside: function() {

		var liEl = (this.currentElement) ? this.currentElement : this.firstElement;
		liEl = liEl.next('li');
		while (liEl) {
			if (!this.inViewport(liEl)) return liEl;
			liEl = liEl.next('li');
		}
		return null;
	},
	getPreviousOutside: function() {
		var liEl = (this.currentElement) ? this.currentElement : this.firstElement;
		liEl = liEl.previous('li');
		while (liEl) {
			if (!this.inViewport(liEl)) return liEl;
			liEl = liEl.previous('li');
		}
		return null;
	},
	getNext: function() {
		if (!this.currentElement) return null;
		var next = this.currentElement.next('li');

        if (next == this.currentElement) return null;
        if (!next) next = this.options.loop ? this.firstElement : null;
		return next;
	},
	getPrevious: function() {
		if (!this.currentElement) return null;
		var prev = this.currentElement.previous('li');

        if (prev == this.currentElement) return null;
        if (!prev) prev = this.options.loop ? this.lastElement : null;
		return prev;
	},
    updateButtonsStyle: function() {
		var next = this.getNext();
		var prev = this.getPrevious();

        if (this.options.nextButton) {
            if (!next) {
                this.options.nextButton.addClassName('disabled');
                if (Object.isFunction(this.options.nextButton.disable)) this.options.nextButton.disable();
            }
		    else {
                this.options.nextButton.removeClassName('disabled');
                if (Object.isFunction(this.options.nextButton.enable)) this.options.nextButton.enable();
            }
        }

        if (this.options.previousButton) {
            if (!prev) {
                this.options.previousButton.addClassName('disabled');
                if (Object.isFunction(this.options.previousButton.disable)) this.options.previousButton.disable();
            }
            else {
                this.options.previousButton.removeClassName('disabled');
                if (Object.isFunction(this.options.previousButton.enable)) this.options.previousButton.enable();
            }
        }
	},
	inViewport: function(liEl) {
		var current = this.firstElement;
		var el_start = 0;
		while (current && current != liEl) {
			el_start += current.getWidth();
			current = current.next('li');
		}

		var vp_start = this.getLeft()-1 || 0;
		var vp_end = vp_start + this.viewport.width;

		var el_end = el_start + liEl.getWidth();

		//console.log([el_start, '-', el_end], ' / ', [vp_start,'-', vp_end])
		return el_start >= vp_start && el_end <= vp_end;

	},
	_hashChangeCheck: function() {

		var curr_offset = UrlHashWriter.getVariable('slider_'+this.element.id);

		if (this.last_selected_offset == curr_offset) return;

		var sibs = this.ulEl.select('li');
        for (var offset = 0; offset < sibs.length; offset++) {
            if (curr_offset == offset) {
                this.last_selected_offset = offset;
                this.moveTo(sibs[offset]);
                break;
            }
		}
	},
	first: function() {
		if (!this.firstElement) return;
		this.moveTo(this.firstElement);
	},
	next: function (event) {
		var next = this.getNext();
		if (next) this.moveTo(next);
	},
	previous: function(event) {
        var prev = this.getPrevious();
		this.moveTo(prev);
	},
	alignMiddle: function() {

		var list = this.ulEl.select('li');

		// Get height of highest image
		var maxheight = list.collect(function(li) {return li.getHeight();}).max();

		// Adjust heights
		for (var i = 0; i < list.length; i++) {
		   var liEl = list[i];
			var top = (maxheight - liEl.getHeight()) / 2;
			liEl.style.marginTop = top + 'px';
		}
		this.element.style.height = maxheight+'px';

		// Align in center
		var wdiff = this.viewport.width - this.getWidth();
		if (wdiff > 0) {
			this.ulEl.style.marginLeft = (wdiff/2)+'px';
		} 
	}
});
