/*
 zoomer.jquery.js
 v 1.03
 --- Authored by James Padolsey for ThemeForest ---
 Got a real bug? Contact me via ThemeForest's messaging system (please specify the version number)
*/

(function($){
    
    /* PLEASE SEE THE DOCUMENTATION
       BEFORE TOUCHING ANYTHING */
    
    var DIRECTORY = 'zoomer/';
    $.zoomer = {};
    $.zoomer.defaultOptions = {
        zoomerClass: '_zoomer',
        zoomSrc: '',
        height: 150,
        width: 150,
        mousewheelZoom: true,
        defaultZoom: 2,
        maxZoom: 5,
        minZoom: 1,
        feedback: function(x,y,zoom){},
        onOver: function(){},
        onOut: function(){},
        zoomerOverlay: {
            className: '_zoomer-overlay',
            shadowWidth: 10,
            shadowOpacity: 0.5,
            /* Must be in "rgb(r,g,b)" format */
            shadowColor: 'rgb(0,0,0)',
            radialOpacity: 0.4,
            /* Must be in "rgb(r,g,b)" format */
            radialColor: 'rgb(0,0,0)'
        }
    };
    
    /* LOAD DEPENDENCIES */
    if (!document.createElement('canvas').getContext) {
        jQuery.ajax({
            url: DIRECTORY + 'excanvas.compiled.js',
            async: false,
            success: function(d){
                jQuery.globalEval(d);
            }
        });
    }
    jQuery.ajax({
        url: DIRECTORY + 'jquery.mousewheel.min.js',
        async: false,
        success: function(d){
            jQuery.globalEval(d);
        }
    });
    
    function createZoomerOverlay(settings) {
        
        settings = $.extend({
            width: 100,
            height: 100,
            shadowWidth: 5,
            radialOpacity: 0.5,
            shadowOpacity: 0.5,
            radialColor: 'rgb(0,0,0)',
            shadowColor: 'rgb(0,0,0)'
        }, settings);
        
        var canvas = $('<canvas/>')[0],
            width = settings.width,
            height = settings.height,
            shadowWidth = settings.shadowWidth,
            radialColor = (function(){
                return settings.radialColor.match(/\d+/g);
            })(),
            sColor = (function(){
                return settings.shadowColor.match(/\d+/g);
            })();
            
        if (window.G_vmlCanvasManager) {
            G_vmlCanvasManager.initElement(canvas);
        }
        canvas.setAttribute('height', height + (shadowWidth*2));
        canvas.setAttribute('width', width + (shadowWidth*2));
        
        function createShadow(x1,y1,x2,y2) {
            var linear = ctx.createLinearGradient(x1,y1,x2,y2);
            linear.addColorStop(0, 'rgba('+sColor.join(',')+',0)');
            linear.addColorStop(1, 'rgba('+sColor.join(',')+',' + settings.shadowOpacity + ')');
            return linear;
        }
        
        function createRadialGradient(x1,y1,r1,x2,y2,r2,from,to) {
            var radial = ctx.createRadialGradient(x1,y1,r1,x2,y2,r2);
            radial.addColorStop(0, from || 'rgba('+radialColor.join(',')+',0)');
            radial.addColorStop(1, to || 'rgba('+radialColor.join(',')+',' + settings.radialOpacity + ')');
            return radial;
        }
        
        function createCorner(x1,y1,r1,x2,y2,r2) {
            return createRadialGradient(x1,y1,r1,x2,y2,r2,'rgba('+sColor.join(',')+',' + settings.shadowOpacity + ')','rgba('+sColor.join(',')+',0)');
        }
        
        var ctx = canvas.getContext('2d'),
            s = shadowWidth,
            _ = ctx;
        
        var mainRX = width/2,
            mainRY = height/2;
            
        _.fillStyle = createRadialGradient(mainRX+s,mainRY+s,0,mainRX+s,mainRY+s,Math.max(mainRY,mainRX));
        _.fillRect(s,s,width,height);
        
        // shadowWidth === 0?
        if (!s) { return canvas; }
        
        // Left:
        _.fillStyle = createShadow(0, 0, s, 0);
        _.fillRect(0, s, s, height);
        // Right:
        _.fillStyle = createShadow(width+(s*2), 0, width+s, 0);
        _.fillRect(width+s, s, s, height);
        // Top:
        _.fillStyle = createShadow(0, 0, 0, s);
        _.fillRect(s, 0, width, s);
        // Bottom:
        _.fillStyle = createShadow(0, height+(s*2), 0, height+s);
        _.fillRect(s, height+s, width, s);
        
        // CornerBottomRight
        _.fillStyle = createCorner(width+s,height+s,0,width+s,height+s,s);
        _.fillRect(width+s,height+s,s,s);
        // CornerTopLeft
        _.fillStyle = createCorner(s,s,0,s,s,s);
        _.fillRect(0,0,s,s);
        // CornerTopRight
        _.fillStyle = createCorner(width+s,s,0,width+s,s,s);
        _.fillRect(width+s,0,s,s);
        // CornerBottomLeft
        _.fillStyle = createCorner(s,height+s,0,s,height+s,s);
        _.fillRect(0,height+s,s,s);
        
        return canvas;
        
    }
    
    $.fn.zoomer = function(uOptions) {
        var o = $.extend(true, {}, $.zoomer.defaultOptions, uOptions);
        
        return this.each(function(){
            
            var thisIMG = $(this),
                mOver = false,
                uid = 't' + (+new Date()),
                mag = $('<div/>').addClass(o.zoomerClass).append(
                    $('<img/>').attr('src', o.zoomSrc || this.src).css({
                        width: this.width * o.defaultZoom,
                        height: this.height * o.defaultZoom
                    })
                ),
                boundX1 = thisIMG.offset().left,
                boundX2 = thisIMG.offset().left + thisIMG.width(),
                boundY1 = thisIMG.offset().top,
                boundY2 = thisIMG.offset().top + thisIMG.height(),
                baseCSS = {
                    position: 'absolute',
                    top: 0,
                    left: 0,
                    display: 'none'
                },
                currentZoom = o.defaultZoom;
            
            mag.css($.extend({
                    zIndex: 998,
                    overflow: 'hidden',
                    width: o.width,
                    height: o.height
                },baseCSS))
                .appendTo('body');
            
            var zImg = $('img', mag);
            
            mag = mag.add(
                $(createZoomerOverlay({
                    width: o.width,
                    height: o.height,
                    shadowWidth: o.zoomerOverlay.shadowWidth,
                    shadowOpacity: o.zoomerOverlay.shadowOpacity,
                    radialOpacity: o.zoomerOverlay.radialOpacity,
                    radialColor: o.zoomerOverlay.radialColor,
                    shadowColor: o.zoomerOverlay.shadowColor
                }))
                    .css($.extend({
                        /* Never thought Opera would give me trouble... */
                        cursor: $.browser.opera ? 'crosshair' : 'url("' + DIRECTORY + 'blank.gif"), crosshair',
                        width: o.width + (o.zoomerOverlay.shadowWidth*2),
                        height: o.height + (o.zoomerOverlay.shadowWidth*2),
                        marginLeft: -o.zoomerOverlay.shadowWidth,
                        marginTop: -o.zoomerOverlay.shadowWidth,
                        zIndex: 999
                    },baseCSS))
                    .addClass(o.zoomerOverlay.className)
                    .bind('mousewheel.zoomer', function(e, delta){
                        if (!o.mousewheelZoom) { return true; }
                        var width = zImg.width(),
                            height = zImg.height(),
                            zoom  = currentZoom * (1 + delta/10);
                        if (zoom < o.minZoom || zoom > o.maxZoom) { return false; }
                        currentZoom = zoom;
                        zImg.css({
                            width: width * (1 + delta/10),
                            height: height * (1 + delta/10)
                        });
                        updateScroll(e);
                        return false;
                    })
                    .bind('mousedown.zoomer', function(){
                        return false;
                    })
                    .appendTo('body')
            );

            var halfOSizeHeight = o.height/2,
                halfOSizeWidth = o.width/2,
                entered = false;
                
            function updatePos(e){
                if (o.stationary) { return; }
                mag.css({
                    top: e.pageY - halfOSizeHeight,
                    left: e.pageX - halfOSizeWidth
                });
            }
            
           function updateScroll(e){
                mag[0].scrollTop = Math.round((e.pageY - thisIMG.offset().top) * currentZoom - halfOSizeHeight);
                mag[0].scrollLeft = Math.round((e.pageX - thisIMG.offset().left) * currentZoom - halfOSizeWidth);
                feedback(e);
            }
            
            function inBounds(e) {
                var x = e.pageX,
                    y = e.pageY;
                return x > boundX1 && x < boundX2 && y > boundY1 && y < boundY2;
            }
            
            function feedback(e) {
                if (!o.feedback) { return; }
                o.feedback(e.pageX - thisIMG.offset().left, e.pageY - thisIMG.offset().top, currentZoom);
            }
            
            $(document)
                .bind('mousemove.zoomer', function(e){
                    if (!inBounds(e)) {
                        if (entered) {
                            entered = false;
                            o.onOut.call(thisIMG);
                            mag.hide();
                        }
                        return;
                    }
                    updatePos(e);
                    updateScroll(e);
                    if (!entered) {
                        entered = true;
                        mag.show();
                        o.onOver.call(thisIMG);
                    }
                })
                .bind('mouseout.zoomer', function(e){
                    try {
                        if (entered && (this === e.target || this === document.documentElement) ) {
                            entered = false;
                            o.onOut.call(thisIMG);
                            mag.hide();
                        }
                    } catch(e) {
                        if (window.console && console.log) {
                            console.log('ERROR', e.message);
                        }
                    }
                });
                
            $(window).resize(function(){
                boundX1 = thisIMG.offset().left;
                boundX2 = thisIMG.offset().left + thisIMG.width();
                boundY1 = thisIMG.offset().top;
                boundY2 = thisIMG.offset().top + thisIMG.height();
            });
        });
    };
})(jQuery);