/**
 * Adding magnifier function to an image
 *
 * The `.uiMagnifier()` widget adds a magnifier to an preview image. The magnified image is passed as
 * additional option and will be shown in a magnified area.
 *
 * The dimensions of the magnifier mover depends on the dimensions of the magnified image,
 * the magnified area and the preview image.
 *
 * ### Examples
 * Add a magnifier on the right side of an image.
 *
 * JavaScript:
 *
 *     ep('#image').uiMagnifier({
 *       'magnifiedPicture':'magnifiedImage.jpg',
 *       'magWidth': 200,
 *       'magHeight': 200,
 *       'dir': 'right'
 *     });
 *
 * HTML:
 *
 *     <img src="Image.jpg" name="Bild" alt="Bild" id="image" />
 *
 *
 * @class jQuery.ui.uiMagnifier
 * @extends jQuery.widget
 *
 * @uses ep
 * @uses jQuery.ui.widget
 * @uses jQuery.event.special.load
 * @uses ep.fn.contextOrientation
 * @since 6.12.0
 */

/**
 * Setting a new preview and magnified image.
 *
 * @param {String} newPreviewImage Specifies path and name of the file containing the new preview image.
 * @param {String} newMagnifiedImage Specifies path and name of the file containing the new magnified image.
 *
 * @method setImage
 * @member jQuery.ui.uiMagnifier
 *
 * @since 6.12.0
 */

/**
 * @cfg {String} magnifiedPicture Specifies path and name of the file containing the magnified image.
 */

/**
 * @cfg {integer} magWidth Width of the magnified area.
 */

/**
 * @cfg {integer} magHeight Height of the magnified area.
 */

/**
 * @cfg {String} magBorder CSS string defining the border of the magnifier mover.
 */

/**
 * @cfg {string} magBG CSS string defining the background of the magnifier mover.
 */

/**
 * @cfg {float} magOpac Number from 0 to 1 defining the opacity of the magnifier mover.
 */

/**
 * @cfg {string} dir Direction where the magnified area is shown relative to the preview image. (posible values 'left', 'right', 'center')
 */

/**
 * @cfg {integer} zIndex Number defining the layer position of the magnified area.
 */

/**
 * @cfg {object} slideshow An object representing a ep.uiSlideshow.
 */

/**
 * See `jQuery.ui.uiMagnifier` for details.
 *
 * @param {Object} [options] A map of additional options pass to the method.
 * @param {String} magnifiedPicture Specifies path and name of the file containing the magnified image.
 * @param {integer} magWidth Width of the magnified area.
 * @param {integer} magHeight Height of the magnified area.
 * @param {String} magBorder CSS string defining the border of the magnifier mover.
 * @param {string} magBG CSS string defining the background of the magnifier mover.
 * @param {float} magOpac Number from 0 to 1 defining the opacity of the magnifier mover.
 * @param {string} dir Direction where the magnified area is shown relative to the preview image. (posible values 'left', 'right', 'center')
 * @param {integer} zIndex Number defining the layer position of the magnified area.
 * @param {object} slideshow An object representing a ep.uiSlideshow.
 *
 * @method uiMagnifier
 * @member jQuery
 *
 * @since 6.12.0
 */

/*jslint browser: true, plusplus: true, nomen: true, ass: true*/
/*global define*/

define("ep/ui/magnifier", [
    "jquery",
    "ep",
    "$dict!ep/dict",
    "$tmpl!ep/ui/magnifier",

    "jquery/ui/widget",
    "ep/ui/core",
    "ep/fn/contextorientation"
], function ($, ep, epDict, tmplMagnifier) {

    'use strict';

    var tExpand = epDict.translate("Expand");

    $.widget("ui.uiMagnifier", {
        options: {
            //    action            : "lightbox",        //
            images: "img", // selector / array of data / data / image node / array of image nodes / jQuery object
            orientation: "right",
            width: 250,
            height: 250
        },

        _create: function () {
            var self = this,
                o = self.options,
                imgs = self.images = ep.ui.imgData(o.images)
                    .on("change.uiMagnifier", $.proxy(self, "_change"))
                    .on("resizestop.uiMagnifier", $.proxy(self, "_resizeZoom"));

            self.animating = false;
            self.refresh = false;
            self.noZoom = false;

            // load template and add element names to instance
            $.extend(self, tmplMagnifier([{
                expand: tExpand
            }])
                .appendTo(self.element)
                .tmplItem("elements"));

            self.cache = {
                box: {
                    width: self.box.innerWidth(),
                    height: self.box.innerHeight()
                },
                boxMag: {},
                ratio: 1
            };

            self.zoom.appendTo("body");

            self.container.on("click.uiMagnifier", function () {
                if (o.action) {
                    imgs.trigger(o.action);
                }
            });

            self._setOptions(o);
        },

        _init: function () {
            this._change();
        },

        destroy: function () {
            var self = this;

            self.images.off(".uiMagnifier");
            self.zoom.remove();
            self.container.remove();
            self._superApply(arguments);
        },

        _setOption: function (key, value) {
            var self = this;

            if (key === "action") {
                self.container.css("cursor", value ? "pointer" : "");
            } else if (key === "width") {
                self.zoom.width(value);
            } else if (key === "height") {
                self.zoom.height(value);
            }

            return this._superApply(arguments);
        },

        _change: function () {
            var self = this,
                curr,
                imgSrc,
                alt;

            if (self.animating) {
                self.refresh = true;
            } else {
                curr = self.images.current();
                alt = curr.node && curr.node.alt ? curr.node.alt : "";

                // Get optimal image size for box and check image by src large
                imgSrc = curr._checkSrcName(curr.srcM, curr.getSrcFor(self.box));

                self.refresh = false;
                self.animating = true;

                self.zoom.hide();
                self.container.off("mouseenter.uiMagnifier mousemove.uiMagnifier mouseleave.uiMagnifier");

                self.boxImg = $('<img alt="' + alt + '" src="' + imgSrc + '"/>')
                    .appendTo(self.boxWrap.empty().hide())
                    .on("load", function () {
                        var imgSrcLarge;

                        self.boxWrap.show();

                        if (self.refresh) {
                            self.animating = false;
                            self._change();
                        } else {
                            curr = self.images.current();
                            imgSrcLarge = curr._checkSrcName(curr.srcM, curr.srcL);

                            self.zoomImg = $('<img alt="' + alt + '" src="' + imgSrcLarge + '"/>')
                                .appendTo(self.zoomWrap.empty())
                                .on("load", function () {
                                    self.animating = false;

                                    if (self.refresh) {
                                        self._change();
                                    } else {
                                        self._resizeZoom();
                                        self.container.on("mouseenter.uiMagnifier", $.proxy(self, "_enterMag"))
                                            .on("mousemove.uiMagnifier", $.proxy(self, "_moveMag"))
                                            .on("mouseleave.uiMagnifier", $.proxy(self, "_leaveMag"));
                                    }
                                });
                        }
                    });

            }
        },

        _resizeZoom: function () {
            var self = this,

                o = self.options,
                cache = self.cache;

            if (!self.zoomImg || !self.boxImg) {
                return;
            }

            cache.ratio = Math.max(self.zoomImg[0].width / self.boxImg[0].width, self.zoomImg[0].height / self.boxImg[0].height);
            self.noZoom = cache.ratio <= 1;

            // Skip resize dom elements if zoom disabled
            if (self.noZoom) {
                return;
            }

            cache.box.width = self.box.innerWidth();
            cache.box.height = self.box.innerHeight();

            self.boxMag
                .outerWidth(o.width / cache.ratio)
                .outerHeight(o.height / cache.ratio);

            cache.boxMag.width = self.boxMag.outerWidth();
            cache.boxMag.height = self.boxMag.outerHeight();

            self.zoom
                .width(o.width)
                .height(o.height);

            self.zoomWrap
                .width(cache.box.width * cache.ratio)
                .height(cache.box.height * cache.ratio);
        },

        _enterMag: function () {
            var self = this;

            // Don't show zoom box if zomm disabled
            if (self.noZoom) {
                return;
            }

            self.boxMag.show();

            self.zoom.contextOrientation(self.box, self.options.orientation, [10, 0])
                .show();
        },

        _moveMag: function (event) {
            var self = this,
                cache = self.cache,
                offset = self.box.offset(),
                top = Math.ceil(Math.min(Math.max(0, (event.pageY - offset.top) - cache.boxMag.height / 2), cache.box.height - cache.boxMag.height)),
                left = Math.ceil(Math.min(Math.max(0, (event.pageX - offset.left) - cache.boxMag.width / 2), cache.box.width - cache.boxMag.width));

            self.boxMag.css({
                top: top + "px",
                left: left + "px"
            });

            self.zoomWrap.css({
                top: -(top * cache.ratio) + "px",
                left: -(left * cache.ratio) + "px"
            });
        },

        _leaveMag: function () {
            var self = this;
            self.boxMag.hide();
            self.zoom.hide();
        }

    });

    return ep;

});