/*
* Zoomy 1.3.3 - jQuery plugin
* http://redeyeops.com/plugins/zoomy
*
* Copyright (c) 2010 Jacob Lowe (http://redeyeoperations.com)
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* Built for jQuery library
* http://jquery.com
*
* Addition fixes and modifications done by Larry Battle ( blarry@bateru.com )
* Code has been refactored and the logic has been corrected.
*
*/


(function ($) {
        
// global zoomys state, Indexed, 0 = no zoom, 1 = zoom;
    
    'use strict';
    var ZoomyS = {
	    count : [],
	    pos: null
	};


    $.fn.zoomy = function (event, options) {

	//defaults && option list
	    var defaults = {
		    zoomSize: 200,
		    round: true,
		    glare: true,
		    clickable: false,
		    attr: 'href',
		    border: '5px solid #999',
		    zoomInit: null,  //callback for when zoom initializes
		    zoomStart: null, // callback for when zoom starts
		    zoomStop: null // callback for when the zoom ends
	    },
		    defaultEvent = 'click',
		    
		    
		    change = {
			
				// Move Zoom Cursor
				
				move : function (ele, zoom, e) {
				    var ratio = function (x, y) {
					    var z = x / y;
					    return z;
					},
					    id = zoom.attr('rel'),
					    l = ele.offset(),
					    theOffset = ZoomyS[id].zoom.border,
					    zoomImgX = ZoomyS[id].zoom.x,
					    zoomImgY = ZoomyS[id].zoom.y,
					    tnImgX = ZoomyS[id].css.width,
					    tnImgY = ZoomyS[id].css.height,
					    zoomSize = options.zoomSize + (theOffset * 2),
					    halfSize = zoomSize / 2,
					    ratioX = ratio(tnImgX, zoomImgX),
					    ratioY = ratio(tnImgY, zoomImgY),
					    stop = halfSize - (halfSize * ratioX) - (theOffset * ratioX) + theOffset,
					    stopPos = function (x) {
						var p = (x - zoomSize - theOffset) + stop;
						return p;
					    },
					    rightStop = stopPos(tnImgX),
					    bottomStop = stopPos(tnImgY),
					    zoomY = zoomImgY - zoomSize,
					    zoomX = zoomImgX - zoomSize,
					    mousePos = function (x, y) {
						var p = x - y - halfSize;    
						return p;
					    },
					    zoomPos = function (x, y, z) {
						var p = ((x - y) / z) - halfSize + theOffset;
						return p;
					    },
					    cdCreate = function (a, b, c, d) {
						var bgPos = '-' + a + 'px ' + '-' + b + 'px',
						    o = {
							backgroundPosition: bgPos,
							left: c,
							top: d
						    };
						return o;
					    },
					    posX = mousePos(e.pageX, l.left),
					    posY = mousePos(e.pageY, l.top),
					    leftX = zoomPos(e.pageX, l.left, ratioX),
					    topY = zoomPos(e.pageY, l.top, ratioY),
					    
					    // Collision Detection Possiblities
					    
					    arrPosb = {
						
						// In the Center
						
						    0 : [leftX, topY, posX, posY],
						    
						// On Left Side
						
						    1 : [0, topY, -stop, posY],
						    
						// On the Top Left Corner
						
						    2 : [0, 0, -stop, -stop],
						    
						//On the Bottom Left Corner
						
						    3 : [0, zoomY, -stop, bottomStop],
						    
						// On the Top
						
						    4 : [leftX, 0, posX, -stop],
						    
						//On the Top Right Corner
						
						    5 : [zoomX, 0, rightStop, -stop],
						    
						//On the Right Side
						    
						    6 : [zoomX, topY, rightStop, posY],
						    
						
						//On the Bottom Right Corner
						
						    7 : [zoomX, zoomY, rightStop, bottomStop],
						    
						//On the Bottom    
						
						    8 : [leftX, zoomY, posX, bottomStop]
					    },
					    
					    // Test for collisions
					    
					    a = -stop <= posX,
					    e2 = -stop > posX,
					    b = -stop <= posY,
					    f = -stop > posY,
					    d = bottomStop > posY,
					    g = bottomStop <= posY,
					    c = rightStop > posX,
					    j = rightStop <= posX,
					    
					    
					    // Results
					    
					    cssArrIndex = (a && b && c && d) ? 0 : (e2) ? (b && d) ? 1 : (f) ? 2 : (g) ? 3 : null : (f) ? (c) ? 4 : 5 : (j) ? (d) ? 6 : 7 : (g) ? 8 : null,
					    
					    //Create CSS object to move Zoomy
					    
					    move = cdCreate(arrPosb[cssArrIndex][0], arrPosb[cssArrIndex][1], arrPosb[cssArrIndex][2], arrPosb[cssArrIndex][3], arrPosb[cssArrIndex][4], arrPosb[cssArrIndex][5]);
					    
					    
					    //Uncomment to see Index number for collision type
					    //console.log(cssArrIndex)
					    
				// And Actual Call
					    
				    zoom.css(move || {});
	
			    },
			    
			    // Change classes for original image effect
			    
			    classes : function (ele) {
				    var i = ele.find('.zoomy').attr('rel');
				    if (ZoomyS[i].state === 0 || ZoomyS[i].state === null) {
					    ele.removeClass('inactive');
				    } else {
					    ele.addClass('inactive');
				    }
			    },
			    
			    // Enter zoom area start up Zoom again
	    
			    enter : function (ele, zoom) {
				    var i = zoom.attr('rel');
				    ZoomyS[i].state = 1;
				    zoom.css('visibility', 'visible');
				    change.classes(ele);
			    },
			    
			    // Leave zoom area
			    
			    leave : function (ele, zoom, x) {
				    var i = zoom.attr('rel');
				    if (x !== null) {
					    ZoomyS[i].state = null;
				    } else {
					    ZoomyS[i].state = 0;
				    }
				    zoom.css('visibility', 'hidden');
				    change.classes(ele);
			    },
			    
			    // Callback handler (startZoom && stopZoom)
			    
			    callback : function (type, zoom) {
				    var callbackFunc = type,
					    zoomId = zoom.attr('rel');
				
				    if (callbackFunc !== null && typeof callbackFunc === 'function') {
					    
					    callbackFunc($.extend({}, ZoomyS[zoomId], ZoomyS.pos));
					    
				    }
				
			    }
			
			
		    },
		    
		    // Styling Object, holds pretty much all styling except for some minor tweeks
		    
		    style = {
			
			    round : function (x, y) {
				var cssObj  = (!options.round) ? 0 : ( x === undefined) ?  options.zoomSize + y / 2 +  'px'  :  options.zoomSize / 2 + 'px ' +  options.zoomSize  / 2 + 'px 0px 0px';
				return cssObj;
			    },
			
			    glare : function (zoom) {
				    zoom.children('span').css({
					    height: options.zoomSize / 2,
					    width: options.zoomSize - 10,
					    margin: ($.browser.msie && parseInt($.browser.version, 10) === 9) ? 0 : '5px auto',
					    'border-radius': style.round(0)
				    });
			    },
			    
			    border: function (zoom) {
                
				var borderRaw = options.border.replace(/^\s*|\s*$/g,''),
				    borderArr = borderRaw.split(' '),
				    interger = parseFloat(borderArr[0]),
				    size = (borderArr.length > 2 && interger * 1 === interger ) ? interger : 0;
				    
				    
				    
				return [borderRaw, size];
			    },
			    
			    params : function (ele, zoom) {
				    var img = ele.children('img'),
				    
					    // TODO: Create function to filter out percents
					    border = style.border(zoom),
					    
					    margin = {
							'marginTop': img.css('margin-top'),
							'marginRight': img.css('margin-right'),
							'marginBottom': img.css('margin-bottom'),
							'marginLeft': img.css('margin-left')
					    },
						
					    floats = {
						    'float': img.css('float')
					    },
					    
					    //Zoomy needs these to work
					    
					    zoomMin = {
						    'display': 'block',
						    height: img.height(),
						    width: img.width(),
						    'position': 'relative'
						
					    },
					    
					    //A lil bit of geneology o.0
					    
					    parentCenter = function () {
						    
						    //Checking for parent text-align center
						    
						    var textAlign = ele.parent('*:first').css('text-align');
						    if (textAlign === 'center') {
							    margin.marginRight = 'auto';
							    margin.marginLeft = 'auto';
							
						    }
	
					    },
					    id = zoom.attr('rel'),
					    css = {};
					    
				    
				    
				    if (floats['float'] === 'none') {
					    parentCenter();
				    }
				    
				    $.extend(css, margin, floats, zoomMin);
				    
				    ZoomyS[id].css = css;
			
				    if (!options.glare) {
					    zoom.children('span').css({
						    height: options.zoomSize - 10,
						    width: options.zoomSize - 10
					    });
				    }
			
				    
				    zoom.css({
					    height: options.zoomSize,
					    width: options.zoomSize,
					    'border-radius': style.round(undefined, border[1]),
					    border: border[0]
				    });
			    
			
			
				    img.css('margin', '0px');
			
			
				    img.one("load", function () {
					    ele.css(ZoomyS[id].css);
				    }).each(function () {
					    if (this.complete || ($.browser.msie && parseInt($.browser.version, 10) === 6)) {
						    $(this).trigger("load");
					    }
				    });
		    
			    }
			
			
			
		    },
		    
		    // Build Object, Elements are added to the DOM here
		    
		    build = {
			
			    // Load Zoom Image
			    
			    image : function (image, zoom) {
				    var id = zoom.attr('rel');
				    //Move the Zoomy out of the screen view while loading img
				    zoom.show().css({top: '-999999px', left: '-999999px'});
			
				    if (zoom.find('img').attr('src') !== image) {
					    zoom.find('img').attr('src', image).load(function () {
						
						    var assets = (options.glare) ?  '<span/>' : '',
							border = style.border(zoom);

						    image = image.replace(/ /g, '%20');
						
						    ZoomyS[id].zoom = {
							    'x': zoom.find('img').width(),
							    'y': zoom.find('img').height(),
							    'border': border[1]
						    };
	
						    zoom.append(assets)
							    .css({
								    'background-image': 'url(' + image + ')'
							    })
							    .find('img')
							    .remove();
						    
						    style.glare(zoom);
						    
					    }).each(function () {
						
						    if (this.complete || ($.browser.msie && parseInt($.browser.version, 10) === 6)) {
							
							    $(this).trigger("load");
							    
						    }
					    });
			
				    }
			    },
			    
			    
		
			    // Add zoom element to page
		
			    zoom : function (ele, i) {
				
				    //Adding Initial State  
				    
				    ZoomyS[i] = {
					    state: null,
					    index : i
				    };
				    
				    ZoomyS.count.push(0);
				    
				    // Picking from the right attibute
				    
				    var image = (typeof (ele.attr(options.attr)) === 'string' && options.attr !== 'href') ?  ele.attr(options.attr) : ele.attr('href'),
					    zoom = null,
					    initCallback = options.zoomInit,
					    eventHandler = function () {
						    var eventlist = [],	//List of Actual Events
							    zoomMove = function (e) {
								
								    change.move(ele, zoom, e);
								    
								    //ZoomyS.pos = e;
								
							    },
							    zoomStart = function () {
								    change.enter(ele, zoom);
								    
								    ele.bind('mousemove', zoomMove);
										    
								    /* Start Zoom Callback */
										
								    change.callback(options.zoomStart, zoom);
							    },
							    zoomStop = function (x) {
								    change.leave(ele, zoom, x);
								    
								    ele.unbind('mousemove', zoomMove);
										    
								    /* Start Zoom Callback */
										
								    change.callback(options.zoomStop, zoom);
							    },
							    events = {		//List of Possible Events
								    event: function (e) {
									
									    ZoomyS.pos = e;
									
									    if (!options.clickable) {
										    e.preventDefault();
									    }
									
									    if (ZoomyS[i].state === 0 || ZoomyS[i].state === null) {
									       
										    zoomStart();
										    
										    //Fix on click show and positioning issues
										    
										    change.move(ele, zoom, e);
										
									    } else if (ZoomyS[i].state === 1 && event !== 'mouseover' && event !== 'mouseenter') {
										    
										    zoomStop(0);
										
									    }
									    
									    
									    
									    
									    
								    },
								    'mouseover': function (e) {
									
									    ZoomyS.pos = e;
									
									    if (ZoomyS[i].state === 0) {
										    zoomStart();
									    }
									    
									    
								
								    },
								    'mouseleave': function (e) {
									
									    ZoomyS.pos = e;
								
									    if (ZoomyS[i].state === 1) {
										
										    zoomStop(null);
											    
									    }
									
								    },
								    'click': function () {
									    return false;
								    }
							    };
						    
						    
						    
						    
						    // Making sure there is only one mouse over event & Click returns false when it suppose to
						    
						    
						    if (event === 'mouseover') {
							    eventlist[event] = events.event;
						    } else {
							    eventlist[event] = events.event;
							    eventlist.mouseover = events.mouseover;
						    }
						    
						    if (!options.clickable && event !== 'click') {
							    eventlist.click = events.click;
						    }
						    eventlist.mouseleave = events.mouseleave;
						    
						    
						    
						    // Binding Events to element
						    
						    ele.bind(eventlist);
						
					    };
					    
				    eventHandler();
					
				    //Creating Zoomy Element
				    ele.addClass('parent-zoom').append('<div class="zoomy zoom-obj-' + i + '" rel="' + i + '"><img id="tmp"/></div>');
				    
				    
				    //Setting the Zoom Variable towards the right zoom object
				    
				    zoom = $('.zoom-obj-' + i);
					    
				    
				    if (initCallback !== null && typeof initCallback === 'function') {
					    initCallback(ele);
				    }
				    
				    // Set basic parameters
				    
				    style.params(ele, zoom);
				    
				    // Load zoom image 
				    
				    build.image(image, zoom);
				    
				    //Event Handler added 1.2
				    
				    
				
			    },
			    
			    // Initialize element to add to page, check for initial image to be loaded
			    
			    init : function (ele, img) {
				    
				    
				    img.one("load", function () {
					
					    // Ready to build zoom
			    
					    build.zoom(ele, ZoomyS.count.length);
			    
				    }).each(function () {
			
					    if (this.complete || ($.browser.msie && parseInt($.browser.version, 10) === 6)) {
				
						    $(this).trigger("load");
				    
					    }
				    });
				
			    }
			
			
			
		    };

	    

		    
		    
		    
		    
	    //Fallback if there is no event but there are options
	
	    if (typeof (event) === 'object' && options === undefined) {
		
		    options = event;

		    event = defaultEvent;
		    
	    } else if (event === undefined) {
		
		    event = defaultEvent;
		    
	    }
	
	    //overriding defaults with options
	
	    options = $.extend(defaults, options);
	    

	    $(this).each(function () {
		
		    var ele = $(this),
			    img = ele.find('img');
			    
			    
		    // Start Building Zoom
		
		    build.init(ele, img);
		   
		    
	    });
	    
	    
    

    };
    
    
}(jQuery));