/*!
            _       ______
           | |     |___  /
  _ __ ___ | |_ ___   / / ___   ___  _ __ ___
 | '_ ` _ \| __/ __| / / / _ \ / _ \| '_ ` _ \
 | | | | | | || (__ / /_| (_) | (_) | | | | | |
 |_| |_| |_|\__\___/_____\___/ \___/|_| |_| |_|

 *
 * mtc_Zoom.js - A jQuery plugin to zoom images on mouse over or tap, based on Cloud Zoom by R Cecco.
 * Verion : 1.5.0
 * Author(s) : Peter Fitzearl, Paul McAvoy
 *
 * Docs: http://wiki.mtcmedia.co.uk/index.php?title=Zoom_Plugin
 * Website: http://www.mtcmedia.co.uk
 *
 */

;(function ($, window, document, undefined) {
    'use strict';

    // Create the defaults once
    var pluginName = 'mtcZoom',
        dataKey = 'plugin_' + pluginName,
        plugin,
        imgSrc,
        imgReplace,
        img,
        portal,
        portalWidth,
        portalHeight,
        zoomedImage,
        defaults = {
            zoomHeight: 'auto',
            zoomWidth: 'auto',
            displayLoading: true,
            enableGallery: true,
            hideMessageOnLaunch: false,
            paddingOffset: 30,
            message: '<i class="fa fa-search-plus"></i> Tap or mouseover to activate zoom'
        };

    $.fn[pluginName] = function (options) {

        // Pop out the error message
        if (this.length === 0) {
            console.error('No elements found for "' + this.selector + '" to enable mtcZoom, check this element exists.');
            return this;
        }

        //  Lets get starts
        if (this.length >= 1) {

            return this.each(function () {
                var plugin, _name;
                plugin = $.data(this, dataKey);
                if (typeof options === 'string') {
                    if (plugin !== null) {
                        if (typeof plugin[_name = options] === 'function') {
                            return plugin[_name]();
                        } else {
                            return void 0;
                        }
                    } else {
                        return void 0;
                    }
                } else if (!plugin) {
                    return $.data(this, dataKey, new Plugin(this, options));
                }
            });

        }

    };

    // The actual plugin constructor
    function Plugin(elem, options) {

        plugin = this;
        plugin.element = elem;
        plugin.settings = $.extend({}, defaults, options);
        plugin._defaults = defaults;
        plugin._name = pluginName;
        plugin.init(elem);

    }

    Plugin.prototype = {

        // Init the plugin on load
        init: function (elem) {

            var el = elem;

            $(el).data('imageLoaded', false);
            $(el).data('portalLoaded', true);

            // If option to show help overlay
            if (plugin.settings.displayLoading) {
                plugin.showTapClickToLoad(el);
            }

            // If gallery image swap enabled
            if (plugin.settings.enableGallery) {
                plugin.setUpGallery(el);
            }

            // wrap large image
            $(el).wrapInner('<div class="zoomContainer"><div class="zoom"></div></div>');

            // Bind the 'kill' event when mouse leaves or touch ends
            $(el).on('mouseleave touchend', function () {

                // Want to hide that help when the zoom loads?
                if (plugin.settings.hideMessageOnLaunch && !$(el).hasClass('disableThisItemZooming')) {
                    $(this).parent().find('.clickToLoad').stop(true, true).fadeIn();
                }

                // Kill the plugin (N.B This is not the destroy)
                plugin.kill(el);

            });

            // Apply the resize event and debounce it to prevent multiple calls
            $(window).on('resize', plugin.debounce(function () {
                plugin.onResize(el);
            }, 300, false));

            // Build its portal
            plugin.buildPortal(el);

            // Bind the mouse enter and touchstart events
            $(el).on('MSPointerMove mouseenter tap', function (ev) {
                // Prevent the nasties
                ev.preventDefault();

                // And now we begin...
                plugin.zoomInit($(this));

            });

            // Set loaded as true
            plugin.loaded = true;

        },

        // Build the portal
        buildPortal: function (el) {

            var zoomContainer = $(el).find('.zoom');

            // Ok portal loading, stop any iterations
            $(el).data('portalLoaded', true);

            // Get rid of the padding and reset
            zoomContainer.css('padding', '');

            // Find the current image
            imgSrc = $(el).find('img').first().attr('src');
            img =  $('<img />');

            // Make sure this image has loaded
            img.on('load', function () {

                // Define the height and width of portal based on options
                if (plugin.settings.zoomHeight === 'auto') {
                    portalHeight = $(el).outerHeight(false);
                } else {
                    portalHeight = plugin.settings.zoomHeight;
                }

                if (plugin.settings.zoomWidth === 'auto') {
                    portalWidth = $(el).outerWidth(false);
                } else {
                    portalWidth = plugin.settings.zoomWidth;
                }

                // Create the portal div if it's not already there
                if ($(el).find('.portal').length < 1) {
                    portal = $('<div class="portal" />');
                } else {
                    portal = $(el).find('.portal');
                }

                // Empty the portal
                portal.empty();

                // Assign it some css
                portal.css({
                    height: portalHeight,
                    maxWidth: portalWidth,
                    width: '100%',
                    position: 'absolute',
                    top: 0,
                    left: 0,
                    overflow: 'hidden'
                });

                // Append the div
                portal.appendTo($(el).find('.zoom'));

                // Add some padding to the bottom if set
                zoomContainer.css('padding-bottom', plugin.settings.paddingOffset + 'px');

            });

            img.attr('src', imgSrc);

        },

        loadImage: function (el) {

            if (!$(el).hasClass('disableThisItemZooming')) {
                // Tell peeps it's loading
                plugin.loadingMessage(true, el);
            }

            // Find the current image
            img = $(el).find('img');

            // Create the large zoomable image
            zoomedImage = $('<img/>').css({
                position: 'absolute',
                top: 0,
                left: 0
            });

            zoomedImage.show();

            // When the image has fully loaded we can hide the loading message;
            zoomedImage.load(function () {
                plugin.loadingMessage(false, el);

                //when image is loaded
                $(el).data('imageLoaded', true);
                zoomedImage.appendTo($(el).find('.portal'));
                zoomedImage.hide();

                if (img.parents('.largeImage').hasClass('disableThisItemZooming')) {
                    $(el).find('.portal > img').hide();
                } else if (img.width() < this.width && img.height() < this.height) {
                    $(el).data('zoomEnabled', true);
                    $(el).find('.portal > img').hide();
                    $(el).find('.portal > img').fadeIn();
                } else {
                    $(el).find('.portal > img').hide();
                }
            });

            zoomedImage.attr('src', img.data('zoom'));

        },

        // Kill whats needed after interaction
        kill: function (el) {

            // Clear timeout to prevent unnecessary load
            clearTimeout(plugin.timer);

            // Hide the image
            $('.portal > img').stop(true, true).fadeOut();
            // remove zooming class
            $(el).removeClass('zooming');

            // Unbind the events
            $(plugin).off('MSPointerMove mousemove touchmove');

            // Show the help overlay again
            if (plugin.settings.displayLoading && !$(el).hasClass('disableThisItemZooming')) {
                $(el).find('.clickToLoad').fadeIn();
            }

        },

        // Start the show
        zoomInit: function (el) {

            if (!($(el).data('portalLoaded'))) {

                plugin.buildPortal(el);

            } else if (!$(el).data('imageLoaded')) {

                $(el).data('zoomEnabled', false);
                plugin.loadImage(el);

            }

             // Want to hide that help when the zoom loads?
            if (plugin.settings.hideMessageOnLaunch) {
                $(el).find('.clickToLoad').stop(true, true).fadeOut();
            }

            // add zooming class to parent
            $(el).addClass('zooming');

             // Now we can add in some movement
            $(el).on('MSPointerMove mousemove touchmove', function (ev) {
                var zWidth,
                    zWidthCache,
                    zHeight,
                    zHeightCache,
                    x,
                    y,
                    nX,
                    nY,
                    touch;

                zWidth = zWidthCache = zoomedImage.width() - portalWidth;
                zHeight = zHeightCache = zoomedImage.height() - portalHeight;

                if ('ontouchstart' in window) {
                    ev.originalEvent.preventDefault();
                } else {
                    ev.preventDefault();
                }

                // if image is loaded and zoomed image size is proper carry on
                if ($(this).data('imageLoaded') === false || $(el).data('zoomEnabled') !== true) {
                    return;
                }

                // position zoomed image and fadeIn
                $(el).find('.portal > img').css({
                    top: 0,
                    left: 0
                }).fadeIn();

                 // If this is a touch event bind the touches
                if ('ontouchstart' in window) {
                    touch = ev.originalEvent.touches[0] || ev.originalEvent.changedTouches[0];
                } else {
                    touch = ev;
                }

                // we need to make the numbers +ve if they are -ve
                if (zWidth < 0) {
                    zWidth = -zWidth;
                }

                if (zHeight < 0) {
                    zHeight = -zHeight;
                }

                x = touch.pageX - $(this).offset().left;
                y = touch.pageY - $(this).offset().top;
                nX = x * (zWidth / portalWidth);
                nY = y * (zHeight / portalHeight);

                if (x < portalWidth && x > 0 && -nX < 0) {
                    /* if zWidth was previously -ve then we
                     * need to reverse the value of nX
                     */

                   if (zWidthCache < 0) {
                       nX = -nX;
                   }

                   // Move the image
                   $(this).find('.portal > img').css({
                       left: -nX
                   });
                }

                if (y < portalHeight && y > 0 && -nY < 0) {
                    /* if zHeight was previously -ve then we
                     * need to reverse the value of nY
                     */

                    if (zHeightCache < 0) {
                        nY = -nY;
                    }

                    // Move the image
                    $(this).find('.portal > img').css({
                        top: -nY
                    });
                }

                ev.stopPropagation();
            });

        },

        // Set up the gallery
        setUpGallery: function (el) {

            // get gallery for this zoom
            var dataAttr = $(el).attr('data-zoom-gallery');

            if ($('.thumbs[data-zoom-gallery="' + dataAttr + '"]').length) {
                $('.thumbs[data-zoom-gallery="' + dataAttr + '"]').addClass('active');
            }

            $('.thumbs[data-zoom-gallery="' + dataAttr + '"]').find('.mtcZoomGallery').each(function () {

                if ($(this).attr('data-large') === $(el).find('img').attr('data-zoom')) {
                    $(this).parents('li').addClass('active');
                }

                $(this).on('click', function (ev) {
                    ev.preventDefault();

                    // Find the new image details
                    var href = $(this).attr('href'),
                        large = $(this).data('large');

                    $(this).parents('li').siblings().removeClass('active');

                    // Find the image to replace
                    imgReplace = $(el).find('img').first();

                    // Do the replace
                    imgReplace.data('zoom', large);
                    imgReplace.attr('src', href);

                    if ($(this).hasClass('disableThisItemZooming')) {
                        imgReplace.parents('.largeImage').addClass('disableThisItemZooming');
                        imgReplace.parents('.largeImage').find('.clickToLoad').stop(true, true).fadeOut();
                    } else {
                        imgReplace.parents('.largeImage').removeClass('disableThisItemZooming');
                        imgReplace.parents('.largeImage').find('.clickToLoad').stop(true, true).fadeIn();
                    }

                    $(this).parents('li').addClass('active');

                    // Everything resets so set the loads as false
                    $(el).data('imageLoaded', false);
                    $(el).data('portalLoaded', false);
                    $(el).data('zoomEnabled', false);

                    // Once the new image is loaded in we can rebuild the portal
                    imgReplace.load(function () {
                        plugin.buildPortal(el);
                    });

                });

            });

        },

        // Create the loading message
        loadingMessage: function (build, el) {

            if (build) {
                var loader = $('<div class="loader" />').html('<img src="/sites/' + $('body').attr('data-site') + '/images/loader.gif" alt="Loading" />');

                loader.appendTo($(el).find('.portal'));
            } else {
                $(el).find('.loader').remove();
            }

        },

        // Create the help overlay
        showTapClickToLoad: function (el) {

            var toLoad = $('<div class="clickToLoad" />').html(plugin.settings.message);

            $(el).css({
                display: 'block'
            });

            toLoad.appendTo($(el));

            if ($(el).hasClass('disableThisItemZooming')) {
                $(el).find('.clickToLoad').hide();
            }

        },

        // Destroy the plugin
        destroy: function () {

            // get gallery for this zoom
            var dataAttr = $(this.element).attr('data-zoom-gallery');

            // Destroy created elements, listeners, etc.
            $(this.element).data('imageLoaded', false);
            $(this.element).data('portalLoaded', false);
            $(this.element).data('zoomEnabled', false);
            $(this.element).find('.portal, .clickToLoad').remove();
            $(this.element).attr('style', '');
            $(this.element).off('click MSPointerMove mousemove touchmove mouseleave touchend mouseenter tap');

            // Destroy gallery for this zoom
            $('.thumbs[data-zoom-gallery="' + dataAttr + '"]').find('.mtcZoomGallery').off('click');
            $('.thumbs[data-zoom-gallery="' + dataAttr + '"]').find('active').removeClass('active');
            $('.thumbs[data-zoom-gallery="' + dataAttr + '"]').removeClass('active');

            // remove zoomContainer and .zoom
            $(this.element).find('.zoom').children().unwrap();
            $(this.element).find('.zoomContainer').children().unwrap();

            // Remove data
            $(this.element).removeData();

        },

        // Reset the plugin (perhaps after screen resize?)
        reset: function (el, settings) {

            $(el).data('imageLoaded', false);
            $(el).data('portalLoaded', false);
            $(el).data('zoomDisabled', false);
            imgReplace.load(function () {
                plugin.buildPortal(el);
            });

        },

        // Debounce function delays function to prevent multiple calls
        debounce: function (func, threshold, execAsap) {

            var timeout;

            return function debounced() {
                var obj = this, args = arguments;
                function delayed() {
                    if (!execAsap) {
                        func.apply(obj, args);
                    }
                    timeout = null;
                }

                if (timeout) {
                    clearTimeout(timeout);
                } else if (execAsap) {
                    func.apply(obj, args);
                }

                timeout = setTimeout(delayed, threshold || 100);
            };

        },

        onResize: function (el) {

            if (plugin.loaded) {
                $(el).data('imageLoaded', false);
                $(el).data('portalLoaded', false);
                plugin.buildPortal(el);
            }

        }

    };

}(jQuery, window, document));
