/* ************************************************************************************* *\
 * The MIT License
 * Copyright (c) 2009 Christian Zenker (http://www.christianbloggt.de)
 * inspired by Fabio Zendhi Nagao's (http://zend.lojcomm.com.br)
 *		iFishEye (http://zendold.lojcomm.com.br/ifisheye/)
 *		check this out if you like this effect and don't want to use TYPO3
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies
 * or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
\* ************************************************************************************* */

/**
 * czFishEye - Unobtrusive Mac-style hover effects
 *
 * for MooTools 1.2
 *
 * @version		0.1
 * 
 * @license		MIT License
 * @author		Christian Zenker <http://www.christianbloggt.de>
 * @copyright	2009 Author
 *
 */

var CzFishEye = new Class({

	/**
	 * Options
	 **/
	options: {
		container:		document,
		classImage:		'iFishEyeImg',
		selectorCaption:'span',
		eyeRadius:		192,
		useAxis:		'both',
		norm:			'p1',
		blankPath:		'images/blank.gif',
		onCreate:		null,
		onTooltipShow:	function(entry) {
			entry
		},
		onTooltipHide:	null
	},
	
	/**
	 * Constructor
	 *
	 * @param	Object		Options
	 */
	initialize: function(options) {
		this.setOptions(options);
		
		// adding a custom, more simple, function to calculate the position
		// might cause some problems, but speeds the whole rendering up
		// the native function 'getPosition' is espacially very slow in FF3 on Linux
		Element.implement({
			getFastPosition: function(){
					var el = this, left = 0, top = 0;
					do {
						left += el.offsetLeft || 0;
						top += el.offsetTop || 0;
						el = el.offsetParent;
					} while (el);
					return {'x': left, 'y': top};
				}
		});
		
		this.entries = [];
		// foreach image in container
		this.options.container.getElements('.'+this.options.classImage).each(function(el, i) {
			if(window.ie && el.getProperty('src').substr(src.length - 3) == "png") {
				//apply AlphaImageLoader if png and Internet Explorer
				obj.setStyle('filter', 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+ src +'",sizingMethod="scale")');
				obj.setProperty('src', this.options.blankPath);
			}
			//add all items to the array
			this.entries.push({
				//size of thumb
				thumb: {
					width: el.getStyle('width').toInt(),
					height: el.getStyle('height').toInt()
				},
				//size of fullsize pic
				fullsize: {
					width: el.getProperty('width'),
					height: el.getProperty('height')
				},
				//the img tag
				img: el,
				//the captions text
				caption: el.getProperty('title')
			});
			el.removeProperties('width', 'height');
		}.bind(this));
		
		//add Event Listeners
		this.options.container.addEvents({
			'mousemove': this.onContainerMouseMove.bindWithEvent(this),
			'mouseleave': this.onContainerMouseLeave.bindWithEvent(this)
		});
		this.fireEvent('onCreate');
	},
	
	/**
	 * Event called when mouse enters the container (don't call this directly)
	 *
	 * @param	Event		event: the event fired
	 **/
	onContainerMouseEnter: function(event) {
	},
	
	/**
	 * Event called when mouse moves in the container (don't call this directly)
	 *
	 * @param	Event		event: the event fired
	 **/
	onContainerMouseMove: function(event) {
		this.entries.each(function(entry, index) {
			entry.img.get('morph').cancel();
			entry.img.setStyles(this.getImageSize(index, event.page));
		}.bind(this));
		return false;
	},
	
	/**
	 * Event called when mouse leaves the container (don't call this directly)
	 *
	 * @param	Event		event: the event fired
	 **/
	onContainerMouseLeave: function(event) {
		this.entries.each(function(entry) {
			//morph back to thumb size
			entry.img.morph(entry.thumb);
		});
	},
	
	/**
	 * get an images size depending on the position of the mouse pointer
	 *
	 * @param	Integer		index: Index of the image in the entries array
	 * @param	Object		pointer: Object {x:UInteger,y:UInteger} that holds coordinates of the mouse pointer
	 *
	 * @return Object {width:UInteger,height:UInteger} holds width and height of the image
	 **/
	getImageSize: function(index, pointer) {
		// get center point of the object
		var dist = this.getDistance(index, pointer);
		
		if(dist > this.options.eyeRadius) {
			//if: element not inside the eye-radius -> thumb size
			return this.entries[index].thumb;
		}else{
			//else: calculate new size
			return this.getSize(index, dist);
		}
	},
	
	/**
	 * calculates distance from the center of one picture to the mouse pointer
	 *
	 * @param	Integer		index: Index of the image in the entries array
	 * @param	Object		pointer: Object {x:UInteger,y:UInteger} that holds coordinates of the mouse pointer
	 *
	 * @return	uint		distance
	 **/
	getDistance: function(index, pointer) {
		var imgPos = this.entries[index].img.getFastPosition(this.options.container), imgSize = this.entries[index].img.getSize();		
		var delta = {
			x: Math.abs(pointer.x - (imgPos.x + imgSize.x/2)),
			y: Math.abs(pointer.y - (imgPos.y + imgSize.y/2))
		};
		
		var dist = 0;
		if(this.options.useAxis.length > 1) {
			//if: calculate distance from both axis
			switch(this.options.norm.toLowerCase()) {
				case 'pn': //maximum norm
					dist = Math.max(delta.x, delta.y);
					break;
				case 'p2': //euclidean norm
					dist = Math.sqrt(Math.pow(delta.x,2) + Math.pow(delta.y,2));
					break;
				case 'p1': //manhattan norm
				default:
					dist = delta.x + delta.y;
					break;
			}
		}else{
			//else: calculate distance from one axis
			dist = delta[this.options.useAxis];
		}
		return Math.round(dist);
	},
	
	/**
	 * calculate new size of an image depending on its distance to the pointer
	 *
	 * @param	Integer		index: Index of the image in the entries array
	 * @param	UInteger	dist: distance to the pointer
	 *
	 * @return Object	{width:UInteger,height:UInteger} size of the object
	 **/
	getSize: function(index, dist) {
		var ratio = (dist/this.options.eyeRadius);
		//calculations uses a linear function
		var size = {
			width: this.entries[index].fullsize.width.toInt() + ratio * (this.entries[index].thumb.width - this.entries[index].fullsize.width),
			height: this.entries[index].fullsize.height.toInt() + ratio * (this.entries[index].thumb.height - this.entries[index].fullsize.height)
		};
		return size;
	}
	
}).implement(new Events,new Options);

