/**
 * DWZoom - use Ajax/JQuery to Zoom and Pan an image
 *        - jQuery is used to dynamically reposition the image by changing the upper-left hand corner relative to the image container
 *        - Ajax is used to request images of different resolutions from the Demandware ImageServer
 * (c) 2009, Demandware Inc.
 */
 
(function($){
    // Constants
    var MAX_ZOOM = 2;
    var MIN_ZOOM = 0;
    var ZOOM_FACTOR = 2; 
    var MIN_WIDTH = 297;   // This is vendor specific and should be changed based on the size of the source images
    
    /* 
     * Objects
     */
    /* object containing information about image
     *   _Image.object - the <img> object itself
     *   _Image.width - image width
     *   _Image.height - image height
     *   _Image.name - non-scaled DW server name
     */
    var _Image = {};
    
    /* args from the calling routine 
     * _args.src - image source
     * _args.animate - boolean to enable animated zooms
     * _args.width - container width
     * _args.height - container height
     * _args.numZoomLevels - MAX_ZOOM will be set to this
     * _args.maxWidth - the largest size you want to zoom to
     */
    var _args = {};
    
    /*
     * Local variables
     */
    var _current_zoom = 0;
    var _container; 
    var _widths = new Array(353, 1177, 1999);  // default values - will possibly be overwritten
    var _new_image = true;
        
    //pan variables
    var _dx; 
    var _dy;
    var _is_panning = false;
    
    // window variables
    var _winHeight;
    var _winWidth;
    var _wincx;
    var _wincy;
    
    /*
     * private functions
     */
    function resize_to_fit(){
        var aspect_ratio = _Image.width / _Image.height;
        var window_ratio = _winWidth /  _winHeight;
        var choose_left = (aspect_ratio > window_ratio);

        if(choose_left){
            _Image.width = _winWidth;
            _Image.height = _winWidth / aspect_ratio;
        }
        else {
            _Image.width = _winHeight * aspect_ratio;
            _Image.height = _winHeight;
        }
        
        // resize and center <img> 
        _Image.object.attr("width", _Image.width)
                     .attr("height", _Image.height);
        _Image.object.css("width", _Image.width)
                     .css("height", _Image.height);
        _Image.object.css("top",-Math.round((_Image.height - _winHeight)/2))
                     .css("left",-Math.round((_Image.width - _winWidth)/2));
        
    }
    
    /**
    * set upper left corner of image
    **/
    function set_upper_left(x,y)
    {
        //clamp coords to window bounds
        if(x > 0) 
            x = 0;
        if(x + _Image.width < _winWidth) 
            x = _winWidth - _Image.width;
        if(_Image.width <= _winWidth) 
            x = -(_Image.width - _winWidth)/2;
 
        if(y > 0) 
            y = 0;
        if(y + _Image.height < _winHeight) 
            y = _winHeight - _Image.height;
        if(_Image.height <= _winHeight) 
            y = -(_Image.height - _winHeight)/2;
        _Image.object.css("top",y + "px").css("left",x + "px");
    };
    
    
    /**
    * set the zoom and (possibly) get a new image and reposition it
    **/
    function zoom_in(new_zoom)
    {
        if ((new_zoom == _current_zoom) || (new_zoom > MAX_ZOOM))
            return;
        ZOOM_FACTOR = _widths[new_zoom] / _widths[new_zoom - 1];
    
        zoom(new_zoom);
    }
      
    function zoom_out(new_zoom)
    {
        if ((new_zoom == _current_zoom) || (new_zoom < MIN_ZOOM))
            return;

        ZOOM_FACTOR = _widths[new_zoom] / _widths[new_zoom+1];    
        zoom(new_zoom);
    }

    function zoom (z)
    {
        // Load new Image!
        if (_widths[z] >= 2000)
        {
            _Image.object.attr('src', _Image.name);
        } else {
            _Image.object.attr('src', _Image.name + '?sw=' + _widths[z]);
        }
        // compute new width/height
        var w = _widths[z];
        var h = _Image.height * ZOOM_FACTOR;
              
        _Image.width = w;
        _Image.height = h;
        _current_zoom = z;

        // compute new upper-left hand corner
        var old_ctr_x = _wincx - parseInt(_Image.object.css("left"));
        var old_ctr_y = _wincy - parseInt(_Image.object.css("top"));
       
        var new_ctr_x = old_ctr_x * ZOOM_FACTOR;
        var new_ctr_y = old_ctr_y * ZOOM_FACTOR;
        
        var x = _wincx - new_ctr_x;
        var y = _wincy - new_ctr_y; 
        
        if(x > 0) 
            x = 0;
        if(x + _Image.width < _winWidth) 
            x = _winWidth - _Image.width;
        if(_Image.width <= _winWidth) 
            x = -(_Image.width - _winWidth)/2;
 
        if(y > 0) 
            y = 0;
        if(y + _Image.height < _winHeight) 
            y = _winHeight - _Image.height;
        if(_Image.height <= _winHeight) 
            y = -(_Image.height - _winHeight)/2;
        
        // Reposition new image and set window widths
        if (_args.animate)
        {
            _Image.object.animate({width:w, height: h, left: x, top:y}, 500);
        } else {
            _Image.object.attr("width",w).attr("height",h).css("width",w+"px").css("height",h+"px");
            _Image.object.css("top",y + "px").css("left",x + "px");
        }
    }
    
    /*
     *   mousdown event handler - start panning image
     */
    function pan_start(e)
    {
        _is_panning = true;
        _container.addClass("pan_cursor");

        _dx = e.pageX - parseInt($(this).css("left"));
        _dy = e.pageY - parseInt($(this).css("top"));
        return false;
    }

    /*
     *  stop panning
     */
    function pan_end(e)
    {
        _container.removeClass("pan_cursor");
        _is_panning=false;
    }    
    
    /*
     *  mousmove event handler - pan image
     */
    function pan(e)
    {
        if(_is_panning){
            var ltop =  e.pageY -_dy;
            var lleft = e.pageX -_dx;
            
            set_upper_left(lleft, ltop);
            return false;
        }
    }
    
    function setWindowFromArgs(_args)
    {
       	if (_args.height == 0 || _args.width == 0)
    	{
    		_winHeight = _container.height();
    		_winWidth = _container.width();
    	} else {
            _winWidth = _args.width;
            _winHeight = _args.height;
        }
        _wincx = _winWidth/2;
        _wincy = _winHeight/2; 
    }
    
    /*
     * Constructor
     */
    $.fn.DWZoom  = function(args)
    {
        _args = args;        
        if(_args.src == null)
            return;
            
        _container = this;
        _container.addClass("cursor");
        
        setWindowFromArgs(_args);
        
        if (_args.numZoomLevels != null && _args.maxWidth != null)
        {
            MAX_ZOOM = _args.numZoomLevels;
            
            var delta = (_args.maxWidth - MIN_WIDTH) / MAX_ZOOM;
            for (var i=0; i <= MAX_ZOOM; i++)
            {
                _widths[i] = MIN_WIDTH + (delta * i);
            }
        }
 
        //init container
        this.css("overflow","hidden");
        
        _new_image = true;
        
        // add the image
        _Image.object = $("<img>").load(function(){
            if (this.naturalWidth != null) 
            {
                _Image.width = _Image.object.width = this.naturalWidth;
                _Image.height = _Image.object.height = this.naturalHeight;
            } else {
                // work around for IE not having 'naturalWidth'
                var run = this.runtimeStyle;
                var mem = { w: run.width, h: run.height }; // keep runtimeStyle
                run.width  = "auto"; // override
                run.height = "auto";
                var w = this.width;
                var h = this.height;
                run.width  = mem.w; // restore
                run.height = mem.h;
                _Image.width = _Image.object.width = w;
                _Image.height = _Image.object.height = h;
            }
            
            if (_new_image) 
            {
                $(this).css("position","absolute")
                    .css("top","0px")
                    .css("left","0px") 
                    .prependTo(_container);
                 
                setWindowFromArgs(_args);
                resize_to_fit();
            }
            
            _new_image = false;
        });
        
        _Image.name = _args.src;
        _Image.object.attr("src", _args.src + '?sw=' + _widths[_current_zoom]).
            mousedown(pan_start).
            mousemove(pan).
            mouseup(pan_end).
            mouseleave(pan_end);
        
        // Add the zoom buttons
        $("<div>").addClass("zoom_in").addClass("common").
            addClass("zoom_button").mousedown(function(){
                zoom_in(_current_zoom + 1); return false;
            }).appendTo(_container);
        
        $("<div>").addClass("zoom_out").addClass("common").
            addClass("zoom_button").mousedown(function(){
                zoom_out(_current_zoom - 1); return false;
            }).appendTo(_container);
       

    };
    
    function load_new (image_container, name) 
    {
        _current_zoom = 0;
        _Image.name = name;
        _Image.object = image_container;
        _Image.object.attr('src', name + '?sw=' + _widths[0]);
        _new_image = true;
    };
    
    /**
    *   externally visible function
    */
    $.fn.DWZoom.load_new  = function(image_container, name) { load_new(image_container, name); };
    
 })(jQuery);

