var Jp_Slideshow = new Class({
	Implements: [Options, Events],
	element: null,
	parent: null,
	triggerPrevious: null,
	triggerNext: null,
	left: 0,
	width: 0,
	panelWidth: 0,
	timer: null,
	steps: [],
	pageLinks: [],
	currentPage: 1,
	pages: 0,
	//slider: null,
	options: {
		//duration: 300,
		onStart: Class.empty,
		onComplete: Class.empty,
		numberOfItems: 7, //number of items to show
		maxspeed: 100, // pixels to move with each iteration
		disabledLinkClass: 'disabled',
		classToHide: null, //a css rule will be written to hide elements with this class while the DOM loads
		classToRemove: null //remove this class when dom is ready
	},
	initialize: function(options) {
		this.addOptions(options);
		this.beforeDomLoad();
	},
	addOptions: function(options) {
		this.setOptions(options);
	},
	start: function(element, navigation) {
		this.element = $(element);
		navigation = $(navigation);
		var lis = navigation.getElements('li');
		if (lis.length > 1) {
			this.triggerPrevious = lis[0];
			this.triggerNext = lis[lis.length - 1];
		}

		if (this.element) {
			this.prepare();
		}
	},
	prepare: function() {
		this.afterDomLoad();
		this.setTriggersAction();

		//set list position
		this.element.setStyles({
			'position': 'absolute'
		});

		//set parent div height and overflow
		var p = this.element.getParent();

		this.parent = {
			element: p,
			width: p.getSize().x,
			left: p.getPosition().x
		}

		//create new div and move the list inside
		this.slider = new Element('div', {
			'styles': {
				'width': p.getStyle('width'),
				'position': 'absolute',
				'overflow': 'hidden'
			}
		});
		this.slider.injectInside(p);
		this.element.injectInside(this.slider);

		//remove the "last" class from the <li> to keep the margins, except for the very last one
		var lis = this.element.getChildren();
		var nbOfLis = lis.length;
		var liNb = 0;
		this.element.getChildren().each(function(e) {
			liNb++;
			//if (liNb != nbOfLis) {
				$(e).removeClass('last');
			//}
		}, liNb, nbOfLis);

		//re-calculate list width (and calculate steps in the mean time)
		var ulWidth = 0;
		this.steps = [];
		if (nbOfLis > 0) {
			//get height
			var heights = lis[0].getStyles('margin-top', 'margin-bottom');
			var liHeight = lis[0].getSize().y;
			for (var property in heights) {
				liHeight += isNaN(parseInt(heights[property])) ? 0 : parseInt(heights[property]);
			}
			p.setStyles({
				'height': liHeight + 'px'
			});
			this.slider.setStyles({
				'height': liHeight + 'px'
			});

			var widths = lis[0].getStyles('border-left-height', 'border-right-height', 'margin-left', 'margin-right');
			for (var property in widths) {
				ulWidth += isNaN(parseInt(widths[property])) ? 0 : parseInt(widths[property]);
			}
			ulWidth += lis[0].getSize().x;

			this.pages = Math.ceil(nbOfLis / this.options.numberOfItems);
			this.panelWidth = ulWidth * this.options.numberOfItems; //panel width
			for (var i = 0; i < this.pages; i++) {
				var step = this.panelWidth * i;
				this.steps.push(step);

				if (this.triggerNext) {
					var li = new Element('li');
					var a = new Element('a', {href: '#', html: i + 1});
					a.addEvent('click', function(evt, page) {
						evt.stop();
						this.slide(page);
					}.bindWithEvent(this, [i + 1]));
					if (i == 0) {
						a.addClass('on');
					}
					a.inject(li);
					li.inject(this.triggerNext, 'before');
					this.pageLinks.push(a);
				}
			}
			ulWidth = this.panelWidth * this.pages; //total width
		}
		this.element.setStyle('width', ulWidth);
		this.width = ulWidth;
		this.updateNavLinks();
	},
	setTriggersAction: function() {
		if (this.triggerPrevious) {
			this.triggerPrevious.addEvent('click', function(evt) {
				evt.stop();
				this.previous();
			}.bindWithEvent(this));
		}
		if (this.triggerNext) {
			this.triggerNext.addEvent('click', function(evt) {
				evt.stop();
				this.next();
			}.bindWithEvent(this));
		}
	},
	previous: function() {
		this.slide(this.currentPage - 1);
	},
	next: function() {
		this.slide(this.currentPage + 1);
	},
	slide: function (page) {
		$clear(this.timer);
		if (this.steps.length < 1) return;

		if (page != this.currentPage) {
			this.currentPage = page;
			this.updateNavLinks();
		}

		var nextStep = this.getNextStep(page);

		if (Math.abs(this.left) < nextStep) {
			// scroll left
			var direction = 'left';
			var speed = (nextStep - Math.abs(this.left)) / this.panelWidth * this.options.maxspeed;
			if (speed < 1) speed = 1;
			if (nextStep <= Math.abs(this.left) + Math.round(speed)) {
				this.move(-(nextStep - Math.abs(this.left)));
				return;
			}
			this.move(-speed);
		}
		else if (Math.abs(this.left) > nextStep) {
			// scroll right
			var direction = 'right';
			var speed = (Math.abs(this.left) - nextStep) / this.panelWidth * this.options.maxspeed;
			if (speed < 1) speed = 1;
			if (nextStep >= Math.abs(this.left) - Math.round(speed)) {
				this.move(Math.abs(this.left) - nextStep);
				return;
			}
			this.move(speed);
		}

		this.timer = this.slide.delay(10, this, page);
	},
	getNextStep: function(page) {
		if (page <= 0) return 0;
		if (page > this.steps.length) page = this.steps.length;
		return this.steps[page - 1];
	},
	move: function (speed) {
		this.left = this.left + speed;
		this.element.setStyles({
			left: this.left
		});
	},
	updateNavLinks: function() {

		if (this.currentPage > 1) {
			this.triggerPrevious.removeClass(this.options.disabledLinkClass);
		}
		else {
			this.triggerPrevious.addClass(this.options.disabledLinkClass);
		}

		if (this.currentPage < this.pages) {
			this.triggerNext.removeClass(this.options.disabledLinkClass);
		}
		else {
			this.triggerNext.addClass(this.options.disabledLinkClass);
		}

		for (var i = 0; i < this.pageLinks.length; i++) {
			if (this.currentPage == i + 1) {
				this.pageLinks[i].addClass('on');
			}
			else {
				this.pageLinks[i].removeClass('on');
			}
		}
	},
	beforeDomLoad: function() {
		//avoid flickering in IE
		if (this.options.classToHide) {
			document.write('<style type="text/css">.' + this.options.classToHide + ' {display: none;}</style>');
		}
	},
	afterDomLoad: function() {
		if (this.options.classToHide) {
			$$('.' + this.options.classToHide).removeClass(this.options.classToHide);
		}
		if (this.options.classToRemove) {
			$$('.' + this.options.classToRemove).removeClass(this.options.classToRemove);
		}
	}
});
