/**
 * ImageZoomer Class
 * javascript class to create a zoom view
 * author: Simon Hiller Fugu GmbH
 */

var ImageZoomer = new Class({
	Implements: [Options],
	
	options: {
		color: '#415968', //not used
		backgroundColor: '#FFF', //not used
		autodragging: true
	},
	
	isDragging: false,
	isIn: false,
	
	initialize: function(container,options){
		this.setOptions(options);
		this.container = $(container);
		this.container.onmouseover = null;
		this.parent = container.getParent('div.paragraph');
		this.thumb = this.parent.getElement('img');
		
		this.bound = {
			start: this.start.bind(this),
			end: this.end.bind(this)
		};
		
		var keys = parseUri(this.thumb.get('src').replace('image_preview','image')).queryKey;
		var path = '/img/zoompicts/'
		for(var key in keys){
			path += (keys[key] + (key!='id'?'_':''));
		}
		path += '.jpg';
		
		
		this.image = new Asset.image(
			path,
			{onload:this.iniZooming.bind(this),onerror: function(){
				this.image = new Asset.image(
					this.thumb.get('src').replace('image_preview','image'),
					{onload:this.iniZooming.bind(this)}
				)
			}.bind(this)}
		);
	},
	
	iniZooming: function(){
		this.zoomer = new Element('div',{'class':'zoomercrob'}).inject(this.container);
		this.viewport = new Element('div',{'class':'viewport'}).inject(this.parent).adopt(this.image).setStyle('height',this.thumb.getSize().y);
		this.vtween = this.viewport.get('tween').addEvent('complete',this.hideViewport.bind(this));
		this.getRatio().updateZoomerCrop();
		var t = this.thumb.getSize();
		this.end().hideViewport(true);
		
		if(this.options.autodragging){
			new AutoDrag(this.zoomer,this.container, {
				modifiers: {x: 'left', y: 'top'},
				grid:1,
				limit: {
					x:[0, (t.x-this.zoomer.getStyle('width').toInt())-2],
					y:[0, (t.y-this.zoomer.getStyle('height').toInt())-2]
				},
				onDrag: this.computeThumbDrag.bind(this),
				onStart: this.startDrag.bind(this),
				onComplete: this.endDrag.bind(this)
			});
		}else{
			new Drag(this.zoomer, {
				modifiers: {x: 'left', y: 'top'},
				grid:1,
				limit: {
					x:[0, (t.x-this.zoomer.getStyle('width').toInt())],
					y:[0, (t.y-this.zoomer.getStyle('height').toInt())]
				},
				onDrag: this.computeThumbDrag.bind(this),
				onStart: this.startDrag.bind(this),
				onComplete: this.endDrag.bind(this)
			});
		}
	},
	
	start: function(){
		this.isIn = true;
		this.container.removeEvent('mouseover',this.bound.iniStart).addEvent('mouseleave',this.bound.end);
		if(this.isDragging)return;
		this.zoomer.get('tween').cancel().set('opacity',0.1);
	},
	startDrag: function(){
		this.isDragging = true;
		//hidde text and co.
		$$(this.parent.getNext('ul')==this.parent.getNext()?this.parent.getNext('ul'):null,this.parent.getChildren('p,h1')).setStyle('opacity',0);
		this.viewport.setStyle('display','block').get('tween').cancel().start('opacity',1);
		this.zoomer.get('tween').cancel().start('opacity',0.5);
	},
	endDrag: function(){
		this.isDragging = false;
		if(!this.isIn)this.end();
	},
	end: function(){
		this.isIn = false;
		this.container.removeEvent('mouseleave',this.bound.end).addEvent('mouseover',this.bound.start);
		if(this.isDragging)return this;
		this.viewport.fade('out');
		this.zoomer.fade('out');
		return this;
	},
	hideViewport: function(force){
		if(force==true){
			this.vtween.cancel().set('opacity',0);
			this.zoomer.get('tween').cancel().set('opacity',0);
		}
		if(this.viewport.getStyle('opacity')==0){
			this.viewport.setStyle('display','none');
			//show text and co.
			$$(this.parent.getNext('ul')==this.parent.getNext()?this.parent.getNext('ul'):null,this.parent.getChildren('p,h1')).setStyle('opacity',1);
		}
	},
	getRatio: function(){
		var i = this.image.getSize();
		var t = this.thumb.getSize();
		var v = this.viewport.getSize();
		
		this.ratio = {
			x:v.x/i.x,
			y:v.y/i.y
		};
		this.zoom = {
			x:i.x/t.x,
			y:i.y/t.y
		}
		return this;
	},
	updateZoomerCrop: function(){
		var t = this.thumb.getSize();
		this.zoomer.setStyles({
			width:Math.min((this.ratio.x*t.x).toInt(),t.x)-2,
			height:Math.min((this.ratio.y*t.y).toInt(),t.y)-2,
			top: 0,left: 0
		});
		return this;
	},
	computeThumbDrag: function(el){
		/* get the zoomed position on thumbnail */
		var pos = el.getPosition(this.container);
		var t = this.thumb.getSize();
		var i = this.image.getSize();
		/* calculate where the zoomed image should be positioned */
		var left = (pos.x*this.zoom.x).toInt();
		var top = (pos.y*this.zoom.y).toInt();
		/* set a few conditions in case the ratio between the thumbnail and the zoomed image is a float number */
		var bigImgLeft = i.x - (t.x*this.ratio.x).toInt();
		var bigImgTop = i.y - (t.y*this.ratio.y).toInt();
		if(left > bigImgLeft)left = bigImgLeft;
		if(top > bigImgTop)top = bigImgTop;
		/* set the position of the zoomed image according to the position of the zoomed area on thumbnail */
		this.setPosition(this.image,-left,-top);
	},
	setDimensions: function(element,width,height){
		element.setStyles({
			'width':width,
			'height':height
		});
	},
	setPosition: function(element,left,top){
		element.setStyles({
			'left':left,
			'top':top
		})
	}
})

var AutoDrag = new Class({
	Extends:Drag,
	initialize: function(element,container,options){
		this.container = container;
		this.parent(element,options);
		this.container.addEvent('mousemove',function(event){this.container.removeEvents('mousemove');this.start(event)}.bind(this));
	},
	start: function(event){
		if (event.rightClick) return;
		if (this.options.preventDefault) event.preventDefault();
		if (this.options.stopPropagation) event.stopPropagation();
		this.mouse.start = event.page;
		var s = this.handles.getSize();
		var p = this.container.getPosition();
		this.fireEvent('beforeStart', this.element);
		var limit = this.options.limit;
		this.limit = {x: [], y: []};
		for (var z in this.options.modifiers){
			if (!this.options.modifiers[z]) continue;
			if (this.options.style) this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
			else this.value.now[z] = this.element[this.options.modifiers[z]];
			if (this.options.invert) this.value.now[z] *= -1;
			this.mouse.pos[z] = p[z] + (s[z]/2).toInt();
			if (limit && limit[z]){
				for (var i = 2; i--; i){
					if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])();
				}
			}
		}
		if ($type(this.options.grid) == 'number') this.options.grid = {x: this.options.grid, y: this.options.grid};
		this.document.addEvent(this.selection, this.bound.eventStop).addEvent('mousemove', this.bound.check);
		this.container.addEvent('mouseleave',this.bound.cancel);
	},
	check: function(event){
		if (this.options.preventDefault) event.preventDefault();
		var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
		if (distance > this.options.snap){
			this.cancel();
			this.document.addEvent('mousemove', this.bound.drag);
			this.container.addEvent('mouseleave', this.bound.stop);
			this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
		}
	},
	attach: function(){
		this.container.addEvent('mouseenter', this.bound.start);
		return this;
	},
	detach: function(){
		this.container.removeEvent('mouseenter', this.bound.start);
		return this;
	},
	cancel: function(event){
		this.document.removeEvent('mousemove', this.bound.check);
		this.container.removeEvent('mouseleave', this.bound.cancel);
		if (event){
			this.document.removeEvent(this.selection, this.bound.eventStop);
			this.fireEvent('cancel', this.element);
		}
	},
	stop: function(event){
		this.document.removeEvent(this.selection, this.bound.eventStop)
				.removeEvent('mousemove', this.bound.drag);
		this.container.removeEvent('mouseleave', this.bound.stop);
		if (event) this.fireEvent('complete', [this.element, event]);
	}
})

// parseUri 1.2.2
// (c) Steven Levithan <stevenlevithan.com>
// MIT License
function parseUri (str) {
	var	o   = parseUri.options,
		m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
		uri = {},
		i   = 14;

	while (i--) uri[o.key[i]] = m[i] || "";

	uri[o.q.name] = {};
	uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
		if ($1) uri[o.q.name][$1] = $2;
	});

	return uri;
};

parseUri.options = {
	strictMode: false,
	key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
	q:   {
		name:   "queryKey",
		parser: /(?:^|&)([^&=]*)=?([^&]*)/g
	},
	parser: {
		strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
		loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
	}
};
