﻿/*
(c) 2011 McKenna Consultants.

Licenced under the MIT:
http://www.opensource.org/licenses/mit-license.php

**************************************/
(function ($) {

    $.fn.mclZoomer = $.fn.MclZoomer = function (variables) {
        var defaults =
		{
		    dsetting:
				{
				    defaultpower: 2,
				    powerrange: [2, 7],
				    magnifiersize: [200, 200],
				    currentPower: 2
				},

		    mousewheelevt: (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel", //FF doesn't recognize mousewheel as of FF3.x
		    popupContainer: null,
		    navigationContainer: null,
		    imageContainer: null,
		    magnifier: null,
		    maginfierImage: null,
		    activeimage: null,
		    biggerImage: null,
		    imageOffset: null,
		    imageScaledSize: null,
		    thumbReplace: { src: '', dst: '' },
		    debug: false,
		    srcImageList: null,
		    srcImages: new Array(),
		    srcImageIndex: 0
		};

        var options = $.extend(defaults, variables);

        //////////////// INIT //////////////// 
        var init = function (zoomWrapper) {
            options.currentPower = options.defaultpower;

            var master = $(zoomWrapper);

            if (options.debug) {
                master.append("<div id='mclzoomer-debug-" + zoomWrapper.id + "' class='mclzoomer-debug'>Debug</div>");
            }

            var srcImg = $($.getImages(zoomWrapper));

            // fit srcImage into its parent container
            var imgContainer = srcImg.parent();
            $.fitImage(zoomWrapper, imgContainer, srcImg, srcImg.width(), srcImg.height());

            // create the two main image sections
            $.createOverlays(zoomWrapper);

            // mouse clicks etc
            $.hookUpEvents(zoomWrapper);

            // setup image
            $.setup(zoomWrapper, srcImg);
        };

        //////////////// GET IMAGES FROM SOURCES //////////////// 
        $.getImages = function (zoomWrapper) {
            // extract source images, if there are some add on clicks
            if (options.srcImageList != null) {
                options.srcImages = options.srcImageList.find('img');
            }

            if (options.srcImages == null) {
                options.srcImages = new Array();
            }

            // See if there is a source image already defined
            var images = $(zoomWrapper).find('img');
            var srcImg;
            $.each(images, function (i, item) {
                srcImg = item;
            });

            options.biggerImage = srcImg;

            if (options.biggerImage.src.length <= 0) {
                options.biggerImage.src = options.srcImages[0].src.replace(options.thumbReplace.src, options.thumbReplace.dst);
            }

            // nope, use first in list
            if (srcImg == null && options.srcImages != null) {
                srcImg = options.srcImages[0];
            }

            // find it in list
            options.srcImageIndex = -1;
            $.each(options.srcImages, function (i, item) {
                if (srcImg != null) {
                    var itemSrc = item.src.replace(options.thumbReplace.src, options.thumbReplace.dst);
                    var srcImgSrc = srcImg.src.replace(options.thumbReplace.src, options.thumbReplace.dst);

                    if (itemSrc == srcImgSrc) {
                        options.srcImageIndex = i;
                        // exists in list so need to make "main" image clickable
                        $.attachImage(zoomWrapper, i, srcImg);
                    }
                }
            });

            if (options.srcImageIndex == -1) {
                options.srcImageIndex = 0;
                options.srcImages.splice(0, 0, srcImg);
            }

            return srcImg;
        };

        //////////////// The popup overlay //////////////// 
        $.createOverlays = function (zoomWrapper, srcImg) {
            var master = $(zoomWrapper);

            master.css({ 'z-index': 10000 });

            master.append("<div id='mclzoomer-popup-" + zoomWrapper.id + "' class='mclzoomer-overlay'></div>");

            options.popupContainer = $('#mclzoomer-popup-' + zoomWrapper.id);
            options.popupContainer.hide();

            // add the background 
            options.popupContainer.append("<div id='mclzoomer-background-" + zoomWrapper.id + "' class='mclzoomer-background'></div>");


            // add the container
            options.popupContainer.append("<div id='mclzoomer-container-" + zoomWrapper.id + "' class='mclzoomer-container'></div>");

            var container = $('#mclzoomer-container-' + zoomWrapper.id);
            container.append("<div id='mclzoomer-imagecontainer-" + zoomWrapper.id + "' class='mclzoomer-imagecontainer'></div>");

            ///////////////// the image
            $.addTheImage(zoomWrapper);

            $.addControls(zoomWrapper, container);

            //////////////// MAGNIFIER
            $.addMagnifier(zoomWrapper);
        };

        //////////////// ADD IMAGE //////////////// 
        $.addTheImage = function (zoomWrapper) {
            options.imageContainer = $('#mclzoomer-imagecontainer-' + zoomWrapper.id);
            options.imageContainer.append("<img id='mclzoomer-showimage-" + zoomWrapper.id + "' class='mclzoomer-showimage' />");

            options.activeimage = $('#mclzoomer-showimage-' + zoomWrapper.id);
        };

        //////////////// BUTTONS //////////////// 
        $.addControls = function (zoomWrapper, container) {
            container.append("<div id='mclzoomer-instruction-" + zoomWrapper.id + "' class='mclzoomer-instructions'>Move mouse over image to magnify. Mouse wheel zoom -/+</div>");

            // close button
            container.append("<div id='mclzoomer-closebtn-" + zoomWrapper.id + "' class='mclzoomer-closebtn'></div>");
            // prev next btns
            container.append("<div id='mclzoomer-nextprevcontainer-" + zoomWrapper.id + "' class='mclzoomer-nextprevcontainer'></div>");

            options.navigationContainer = $('#mclzoomer-nextprevcontainer-' + zoomWrapper.id);

            options.navigationContainer.append("<div id='mclzoomer-prevbtn-" + zoomWrapper.id + "' class='mclzoomer-prevbtn'></div>");
            options.navigationContainer.append("<div id='mclzoomer-nextbtn-" + zoomWrapper.id + "' class='mclzoomer-nextbtn'></div>");
        };

        //////////////// Magnifier //////////////// 
        $.addMagnifier = function (zoomWrapper) {
            var magnifier = $("<div class='mclzoomer-magnifier' id='mclzoomer-maginfier-outer-" + zoomWrapper.id + "' />")
                .appendTo(document.body);

            magnifier.css({ 'z-index': 10001 });

            magnifier.append("<img class='mclzoomer-magnifier-image' id='mclzoomer-maginfier-image-" + zoomWrapper.id + "' />");

            options.magnifier = magnifier;
            options.magnifierImage = $("#mclzoomer-maginfier-image-" + zoomWrapper.id);

            magnifier.css(
                {
                    'width': options.magnifiersize[0],
                    'height': options.magnifiersize[1]
                });

            magnifier.hide();
        };

        //////////////// Aspect fit the image to the parent container //////////////// 
        $.fitImage = function (zoomWrapper, container, theImage, imgWidth, imgHeight) {
            var targetWidth = container.width() - 2;
            var targetHeight = container.height() - 2;


            $.debugWriteLine(zoomWrapper, 'Container width: ' + targetWidth + ' height: ' + targetHeight);
            $.debugWriteLine(zoomWrapper, 'Image width: ' + imgWidth + ' height: ' + imgHeight);

            // ok now fit image to box
            if (imgWidth > 0 && imgHeight > 0 && targetHeight > 0 && targetWidth > 0) {
                var X = targetWidth / imgWidth;
                var Y = targetHeight / imgHeight;

                // how much to scale down by if anything
                var Scale = Math.min(X, Y);

                var finalHeight = parseInt(imgHeight * Scale);
                var finalWidth = parseInt(imgWidth * Scale);

                var deltaWidth = Math.max(targetWidth - finalWidth, 0) / 2;
                var deltaHeight = Math.max(targetHeight - finalHeight, 0) / 2;

                // within tolerance of 10px?
                if (deltaWidth <= 10) {
                    deltaWidth = 0;
                    finalWidth = targetWidth;
                }

                if (deltaHeight <= 10) {
                    deltaHeight = 0;
                    finalHeight = targetHeight;
                }

                theImage.css(
                    {
                        /*'position': 'absolute',*/
                        'left': deltaWidth,
                        'top': deltaHeight,
                        'width': finalWidth,
                        'height': finalHeight
                    });

                $.debugWriteLine(zoomWrapper, 'fit w: ' + finalWidth + ' h: ' + finalHeight + ' left: ' + deltaWidth + ' top: ' + deltaHeight);

                options.imageOffset = theImage.offset();
                options.imageScaledSize = { width: finalWidth, height: finalHeight };
            }


        };

        //////////////// hookup events ///////////////////////////////////////
        $.hookUpEvents = function (zoomWrapper) {
            $(document).unbind('mousemove.trackmagnifier').bind('mousemove.trackmagnifier', function (e) {
                $.moveMagnifier(zoomWrapper, e);
            });

            options.magnifier.bind(options.mousewheelevt, function (e) {
                //bind mousewheel event to magnifier
                var delta = e.detail ? e.detail * (-120) : e.wheelDelta; //delta returns +120 when wheel is scrolled up, -120 when scrolled down
                if (delta <= -120) {
                    options.currentPower = Math.max(options.currentPower - 0.5, options.powerrange[0]);
                } else { //zoom in
                    options.currentPower = Math.min(options.currentPower + 0.5, options.powerrange[1]);
                }

                e.preventDefault();
                $.moveMagnifier(zoomWrapper, e);
            });

            $('#mclzoomer-prevbtn-' + zoomWrapper.id).click(function () {
                $.prevImage(zoomWrapper);
            });

            $('#mclzoomer-nextbtn-' + zoomWrapper.id).click(function () {
                $.nextImage(zoomWrapper);
            });

            $('#mclzoomer-closebtn-' + zoomWrapper.id).click(function () {
                $.closePopup(zoomWrapper);
            });

            $.each(options.srcImages, function (i, item) {
                $.attachImage(zoomWrapper, i, item);
            });
        };

        //////////////// MOVE AND ZOOM ///////////////////////////////////////
        $.attachImage = function (zoomWrapper, i, item) {
            $(item).css(
                {
                    cursor: 'pointer'
                });

            $(item).click(function () {
                $.showImage(zoomWrapper, i);
            });

            $(item).mouseover(function () {
                // Commented out by Nick 31/12/2011 as it seems to cause problems on the product page
                //$.hoverImage(zoomWrapper, i);
            });
        };

        //////////////// MOVE AND ZOOM ///////////////////////////////////////
        $.moveMagnifier = function (zoomWrapper, e) {
            var mag = options.magnifier;

            if (options.popupContainer.is(":visible")) {
                var magImage = options.magnifierImage;
                var pos = options.imageOffset;
                var tol = 5;

                var inside = $.pointContains(e.pageX, e.pageY, pos.left - tol, pos.top - tol, options.imageScaledSize.width + tol * 2, options.imageScaledSize.height + tol * 2);

                var navPos = options.navigationContainer.offset();
                var insideNav = $.pointContains(e.pageX, e.pageY, navPos.left, navPos.top, options.navigationContainer.width(), options.navigationContainer.height());

                var closeBtn = $('#mclzoomer-closebtn-' + zoomWrapper.id);
                var closePos = closeBtn.offset();
                var insideClose = $.pointContains(e.pageX, e.pageY, closePos.left, closePos.top, closeBtn.width(), closeBtn.height());
                if (inside && !insideNav && !insideClose) {
                    var boxWidth = options.magnifiersize[0] / 2;
                    var boxHeight = options.magnifiersize[1] / 2;

                    var tx = (e.pageX - pos.left);
                    var ty = (e.pageY - pos.top);

                    var imgWidth = options.imageScaledSize.width * options.currentPower;
                    var imgHeight = options.imageScaledSize.height * options.currentPower;

                    tx *= options.currentPower;
                    ty *= options.currentPower;

                    tx -= boxWidth;
                    ty -= boxHeight;

                    mag.css(
                        {
                            left: (e.pageX - boxWidth) + 'px',
                            top: (e.pageY - boxHeight) + 'px'
                        }).show();

                    magImage.css(
                        {
                            left: -tx + 'px',
                            top: -ty + 'px',
                            width: imgWidth,
                            height: imgHeight
                        });

                    //	$.debugWriteLine(zoomWrapper,  'tx: ' + tx + ' ty: ' + ty);
                } else {
                    mag.hide();
                }
            } else {
                mag.hide();
            }
        };


        ////////////////  SHOW NEXT IMAGE //////////////// 
        $.showImage = function (zoomWrapper, i) {
            options.srcImageIndex = i;

            options.popupContainer.show();

            $.setup(zoomWrapper, options.srcImages[options.srcImageIndex]);
        };

        ////////////////  SHOW NEXT IMAGE //////////////// 
        $.hoverImage = function (zoomWrapper, i) {
            options.srcImageIndex = i;

            if (options.biggerImage != null) {
                var srcImg = options.srcImages[options.srcImageIndex];

                var urlSrc = srcImg.src.replace(options.thumbReplace.src, options.thumbReplace.dst);

                $(options.biggerImage).attr('src', urlSrc);

                var imgContainer = $(options.biggerImage).parent();
                $.fitImage(zoomWrapper, imgContainer, $(options.biggerImage), $(srcImg).width(), $(srcImg).height());
            }
        };

        ////////////////  SHOW NEXT IMAGE //////////////// 
        $.nextImage = function (zoomWrapper) {
            options.srcImageIndex = (options.srcImageIndex + 1) % options.srcImages.length;

            $.setup(zoomWrapper, options.srcImages[options.srcImageIndex]);
        };

        ////////////////  SHOW PREV IMAGE //////////////// 
        $.prevImage = function (zoomWrapper) {
            if (options.srcImageIndex > 0) {
                options.srcImageIndex = (options.srcImageIndex - 1) % options.srcImages.length;
            } else {
                options.srcImageIndex = options.srcImages.length - 1;
            }

            $.setup(zoomWrapper, options.srcImages[options.srcImageIndex]);
        };

        ////////////////  SHOW NEXT IMAGE //////////////// 
        $.closePopup = function (zoomWrapper) {
            options.popupContainer.hide();
        };

        ////////////////  sets up the two main screens //////////////// 
        $.setup = function (zoomWrapper, srcImg) {
            if (srcImg.src != null) {
                var urlSrc = srcImg.src.replace(options.thumbReplace.src, options.thumbReplace.dst);
                $.debugWriteLine(zoomWrapper, 'Setup Image : ' + urlSrc);
                options.magnifierImage.attr('src', urlSrc);
                options.activeimage.attr('src', urlSrc);

                $.fitImage(zoomWrapper, options.imageContainer, options.activeimage, $(srcImg).width(), $(srcImg).height());

                var multi = false;
                if (options.srcImages != null) {
                    if (options.srcImages.length > 1) {
                        multi = true;
                    }
                }

                if (multi) {
                    options.navigationContainer.show();
                } else {
                    options.navigationContainer.hide();
                }
            }
        };

        //////////////// 
        $.debugWriteLine = function (zoomWrapper, txt) {
            if (options.debug) {
                var dbg = $('#mclzoomer-debug-' + zoomWrapper.id);
                dbg.append('<br/>' + txt);
            }
        };

        ////////////////  Test to see if a point is inside an element //////////////// 
        $.pointContains = function (posX, posY, targetX, targetY, width, height) {
            return (posX >= targetX && posX <= (targetX + width)
                && posY >= targetY && posY <= (targetY + height));
        };

        this.each(function () { init(this); });
    };

})(jQuery);
	
