var ProductSelector = new Class({

	Implements: [ Options, Events ],
	
	options: {
		scaling: {
			text: 1.2
		},
		sizes: {
			slide: {
				x: 204,
				topFactor: 1.35
			},
			shadow: {
				xFactor: 1.11,
				yFactor: 1
			},
			image: {
				x: 192,
				xDelta: 60,
				y: 98,
				yDelta: 60
			},
			icon: {
				x: 37,
				xDelta: 12,
				y: 41,
				yDelta: 12
			}
		},
		reflection: {
			height: 0.33
		},
		slides: 3,
		colors: {
			inactive: '#161824',
			active: '#3a7dda'
		},
		shadowSrc: '/files/cupori/img/ps-shadow.png',
		blankSrc: '/files/cupori/img/blank.gif'
	},
	
	initialize: function(options) {
		this.bound = {
			moveNext: this.moveNext.bind(this),
			movePrevious: this.movePrevious.bind(this)
		};
		this.setOptions(options);
		this.colorSteps = Array(10);
		this.colors = {};
		$each(this.options.colors, function(val, key) {
			this.colors[key] = new Color(val);
		}, this);
		for (var i = 0, l = this.colorSteps.length - 1; i <= l; ++i) {
			this.colorSteps[i] = this.colors.inactive.mix(this.colors.active, i / l * 100);
		}
		this.elements = {};
		this.slides = [];
		this.activeSlides = [];
		this.at = undefined;
		this.toElement();
	},
	
	addSlide: function(slide) {
		if (location.hash.substr(1) == slide.id) this.at = this.slides.length;
		var data = this.createSlide(slide, this.slides.length);
		data.fx = new ProductSelector.ScaleFX(data, this);
		this.elements.allSlides.adopt(data.container);
		this.slides.push(data);
		return this;
	},
	
	/**
	 * @param slide { id, name, icon, image, link }
	 */
	createSlide: function(slide, index) {
		var container = new Element('div', {
			'class': 'slide'
		});
		var link = new Element('a', {
			href: slide.link,
			events: {
				mouseenter: function() {
					cover.fade(0.25);
				},
				mouseleave: function() {
					cover.fade(0);
				},
				focus: function(e) {
					e.target.blur();
				}
			}
		});
		link.addEvent('click', function(e) {
			e.stop();
			this.move(this.at + this.relativePosition(this.slides[index]));
		}.bind(this));
		var shadow = new Element('img', {
			'class': 'shadow',
			src: this.options.shadowSrc,
			styles: {
				opacity: 0
			}
		});
		if (Browser.Engine.trident4) {
			shadow.src = this.options.blankSrc;
			shadow.runtimeStyle.backgroundImage = 'none';
			shadow.runtimeStyle.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + this.options.shadowSrc + '", sizingMode=scale)';
		}
		var image = new Element('span', {
			'class': 'image'
		});
		var actualImage = new Image();
		actualImage.src = slide.image;
		image.adopt(actualImage);
		var cover = new Element('span', {
			'class': 'cover',
			tween: {
				duration: 'short'
			},
			styles: {
				opacity: 0
			}
		});
		var icon, iconShadow;
		if (slide.icon) {
			icon = new Element('span', {
				'class': 'icon'
			}).adopt(
				new Element('img', {
					src: slide.icon	
				})
			);
			iconShadow = new Element('span', {
				'class': 'icon-shadow',
				styles: {
					opacity: 0.6
				}
			});
		}
		var reflection = new Element('span', {
			'class': 'reflection'
		});
		reflection.adopt(this.createReflection(slide.image, this.options.sizes.image.x, this.options.sizes.image.y * this.options.reflection.height));
		var label = slide.name && new Element('span', {
			'class': 'label',
			text: slide.name
		});
		container.adopt(link.adopt(shadow, image.adopt(cover), icon && icon.adopt(iconShadow), reflection, label));
		return {
			data: slide,
			container: container,
			link: link,
			image: image,
			cover: cover,
			icon: icon,
			label: label,
			shadow: shadow
		};
	},
	
	createReflection: function(src) {
		var img = new Image();
		var width = this.options.sizes.image.x;
		var realHeight = this.options.sizes.image.y;
		var height = realHeight * this.options.reflection.height;
		if (Browser.Engine.trident) {
			img.src = src;
			img.width = width;
			img.style.filter = 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity=20, style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy=' + (height / realHeight * 100 * 0.7) + ')';
			return img;
		}
		var canvas = document.createElement('canvas');
		if (!canvas || !canvas.getContext) return null;
		canvas.width = width;
		canvas.height = height;
		var g = canvas.getContext('2d');
		img.onload = function() {
			g.translate(0, height);
			g.scale(1, -1);
			g.drawImage(img, 0, canvas.height - img.height + 1, canvas.width, img.height);
			g.globalCompositeOperation = 'destination-out';
			var gradient = g.createLinearGradient(0, 0, 0, height);
			gradient.addColorStop(1, 'rgba(0, 0, 0, 0.8)');
			gradient.addColorStop(0.2, 'rgba(0, 0, 0, 1)');
			g.fillStyle = gradient;
			g.fillRect(0, 0, width, height);
		}
		img.src = src;
		return canvas;
	},
	
	importSlides: function(slides) {
		$each(slides, this.addSlide, this);
		return this;
	},
	
	balance: function() {
		var sideLimit = (this.slides.length - 1) / 2;
		var currentLeft = this.slides[this.at].container.getAllPrevious().length;
		while (currentLeft < sideLimit) {
			this.elements.allSlides.getLast().inject(this.elements.allSlides, 'top');
			++currentLeft;
		}
		while (currentLeft > sideLimit) {
			this.elements.allSlides.getFirst().inject(this.elements.allSlides, 'bottom');
			--currentLeft;
		}
	},
	
	limit: function(to) {
		if (to < 0) to += this.slides.length;
		return this.at = to % this.slides.length;
	},
	
	left: function(position) {
		return -(position - Math.floor(this.options.slides / 2)) * this.options.sizes.slide.x;
	},
	
	move: function(to) {
		var mid = Math.floor((this.slides.length - 1) / 2);
		var fromPosition = this.left(mid + this.at - to);
		var toPosition = this.left(mid);
		var currentSlide = this.slides[this.at];
		if (!currentSlide) return;
		var toSlide = this.slides[this.at = this.limit(to)];
		this.fireEvent('beforeMove', [ toSlide, currentSlide ]);
		currentSlide.container.removeClass('active-slide');
		currentSlide.fx.start(1, 0);
		toSlide.fx.start(0, 1).chain(function() {
			toSlide.container.addClass('active-slide');
			this.fireEvent('move', [ toSlide, currentSlide ]);
		}.bind(this));
		this.elements.allSlides.setStyle('left', fromPosition);
		this.balance();
		this.elements.allSlides.tween('left', fromPosition, toPosition);
	},
	
	moveNext: function(e) {
		if (e) e.stop();
		e.target.blur();
		this.move(this.at + 1);
	},
	
	movePrevious: function(e) {
		if (e) e.stop();
		e.target.blur();
		this.move(this.at - 1);
	},
	
	prepare: function() {
		if (isNaN(this.at)) this.at = Math.floor(this.slides.length / 2);
		else this.balance();
		var pos = this.at;
		this.move(pos);
	},
	
	render: function() {
		this.prepare();
		this.fireEvent('ready');
		return this;
	},
	
	relativePosition: function(slide) {
		return slide.container.getAllPrevious().length - this.slides[this.at].container.getAllPrevious().length;
	},
	
	toElement: function() {
		if (this.element) return this.element;
		var container = new Element('div', {
			'class': 'slides'
		});
		var controls = new Element('div', {
			'class': 'controls'
		});
		var toPrevious = this.elements.toPrevious = new Element('a', {
			'class': 'previous',
			href: '#previous-slide',
			tween: {
				duration: 'short'
			},
			events: {
				click: this.bound.movePrevious,
				mouseenter: function() {
					this.tween('background-color', '#ff5421');
				},
				mouseleave: function() {
					this.tween('background-color', '#FF3200');
				}
			}
		});
		var toNext = this.elements.toNext = new Element('a', {
			'class': 'next',
			href: '#next-slide',
			tween: {
				duration: 'short'
			},
			events: {
				click: this.bound.moveNext,
				mouseenter: function() {
					this.tween('background-color', '#ff5421');
				},
				mouseleave: function() {
					this.tween('background-color', '#FF3200');
				}
			}
		});
		var slideMask = this.elements.slideMask = new Element('div', {
			'class': 'slide-wrapper'
		});
		var slideContainer = this.elements.allSlides = new Element('div', {
			'class': 'all-slides',
			tween: {
				duration: 350,
				transition: 'circ:in:out'
			}
		});
		container.adopt(controls.adopt(toPrevious, toNext), slideMask.adopt(slideContainer));
		return this.element = container;
	}

});

ProductSelector.ScaleFX = new Class({
	
	Extends: Fx,
	
	initialize: function(slide, selector, options) {
		this.slide = slide;
		this.selector = selector;
		this.parent(options || {
			transition: 'circ:in:out',
			link: 'cancel',
			duration: 350
		});
	},
	
	set: function(to) {
		var slide = this.slide;
		var options = this.selector.options, sizes = options.sizes, scaling = options.scaling, colors = this.selector.colorSteps;
		slide.container.setStyles({
			zIndex: to * 100
		});
		var w = sizes.image.x + sizes.image.xDelta * to;
		var h = sizes.image.y + sizes.image.yDelta * to;
		slide.shadow.setStyles({
			width: sizes.shadow.xFactor * w,
			height: sizes.shadow.yFactor * h
		});
		if (!Browser.Engine.trident) slide.shadow.set('opacity', to);
		else if (Browser.Engine.trident4) slide.shadow.set('opacity', to == 1);
		else slide.shadow.set('opacity', !(to == 0));
		slide.link.setStyles({
			left: -(sizes.image.xDelta * to) / 2,
			top: -(sizes.image.yDelta * to) / 2 * sizes.slide.topFactor
		});
		slide.image.setStyles({
			width: w,
			height: h
		});
		if (slide.icon) slide.icon.setStyles({
			width: sizes.icon.x + sizes.icon.xDelta * to,
			height: sizes.icon.y + sizes.icon.yDelta * to
		});
		if (slide.label) slide.label.setStyles({
			color: colors[Math.round((colors.length - 1) * to)],
			fontSize: (1 + (scaling.text - 1) * to) * 100 + '%'
		});
		return this;
	}

});
