/**
 * Magnifies a small image
 *
 */

if(!$defined(Ah)) Ah = { Effects: {} };

Ah.Effects.Magnifier = new Class({
    
	     Implements: [Events, Options],
		
        name: 'Magnifier',
        id: null,
        el: null,
        small_el: null,
        large_wrapper_el: null,
        large_el: null,
        highlight: null,
        original: null,
        magnified: null,
        highlight_width: null,
        highlight_height: null,
        position_modifier: null,
        original_x: null,
        original_y: null,
        original_size: null,
        original_loaded: false,
        loaded: false,
        loading_message: null,
        waiting_for_load: false,
        
        options: {
            id: null,
			      width: null,
            height: null,
            horizontal: 'right',
            vertical: 'center',
            center_image: true,
            loading_text: 'Loading...'
        },
        
        initialize: function(image_el, src, options){
            this.original = $(image_el);
            this.setOptions(options);
            this.id = this.options.id || this.original.id || this.name;
            this.preloadOriginal();
            this.preloadMagnified(src);
            this.fireEvent('onInitialize');
        },
        
        determineSizeAndPositioning: function(){
            this.highlight_width = this.original_size.width * (this.options.width / this.magnified.width);
            this.highlight_height = this.original_size.height * (this.options.height / this.magnified.height);
            this.position_modifier = this.magnified.width / this.original_size.width;
            var position = this.original.getPosition();
            this.original_x = position.x;
            this.original_y = position.y;
        },
        
        preloadOriginal: function(){
            this.loaded_original = new Asset.image( this.original.src, { 
                                                                     onload: this.onOriginalLoad.bind(this)
                                                                     } );
        },
        
        preloadMagnified: function(src){
            this.magnified = new Asset.image( src, { 'class': 'magnifier_magnified_image', 
                                                                     alt: 'Magnified image', 
                                                                     onload: this.onMagnifiedLoad.bind(this)
                                                                     } );
        },
        
        onOriginalLoad: function(){
           this.original_loaded = true;
           var original_size = this.original.getSize();
            this.original_size = { width: original_size.x, height: original_size.y };
            this.options.width = this.options.width || this.original_size.width;
            this.options.height = this.options.height || this.original_size.height;
            this.createContainer();
            this.original.addEvent('mouseenter', this.onMouseOver.bindWithEvent(this));
        },
        
        onMagnifiedLoad: function(){
           this.loaded = true;
           this.original.addEvent('mousemove', this.onMouseMove.bindWithEvent(this));
           if(this.waiting_for_load) this.onMouseOver.attempt(this.waiting_for_load, this);
        },
        
        onMouseOver: function(e){
            this.removeLoadingMessage();
            if(!this.loaded){
               this.waiting_for_load = e;
               this.createLoadingMessage();
               return false;
            }
            if(!$chk(this.highlight)) this.createHighlight();
            if(!$chk(this.large_el)) this.createLarge();
            this.position(e);
        },
        
        onMouseMove: function(e){
            if(!$chk(this.highlight)) this.createHighlight();
            this.position(e);
        },
        
        onMouseOut: function(e){
            if($chk(this.highlight)){ 
              this.highlight.remove();
              this.highlight = null;
            }
            if($chk(this.large_wrapper_el)){ 
              this.large_wrapper_el.remove();
              this.large_wrapper_el = null;
              this.large_el = null;
            }
        },
        
        position: function(e){
            var mx = 0;
            var my = 0;
            var x = 0;
            var y = 0;
            var half_w = this.highlight_width / 2;
            var half_h = this.highlight_height / 2;
            var highlight_real_size = this.highlight.getSize();
            var half_x = highlight_real_size.x / 2;
            var half_y = highlight_real_size.y / 2;
            var mouse = this.getMouseOffset(e);
            var x_is_between = ( (mouse.x >= half_x) && (mouse.x <= (this.original_size.width - half_x)) ) ? true : false;
            var x_is_greater = (mouse.x > (this.original_size.width - half_x)) ? true : false;
            switch(true){
               case x_is_between:
                   mx = mouse.x - half_w;
                   x = mouse.x - half_x;
                   break;
               case x_is_greater:
                   mx = this.original_size.width - this.highlight_width;
                   x = this.original_size.width - highlight_real_size.x;
                   break;
            }
            var y_is_between = ( (mouse.y >= half_y) && (mouse.y <= (this.original_size.height - half_y)) ) ? true : false;
            var y_is_greater = (mouse.y > (this.original_size.height - half_y)) ? true : false;
            switch(true){
               case y_is_between:
                   my = mouse.y - half_h;
                   y = mouse.y - half_y;
                   break;
               case y_is_greater:
                   my = this.original_size.height - this.highlight_height;
                   y = this.original_size.height - highlight_real_size.y;
                   break;
            }
            this.highlight.setStyle('left', x);
            this.highlight.setStyle('top', y);
            this.magnified.setStyle('left', 0 - (mx * this.position_modifier));
            this.magnified.setStyle('top', 0 - (my * this.position_modifier));
        },      
        
        getMouseOffset: function(e){
            var x = e.page.x - this.original_x;
            var y = e.page.y - this.original_y;
            return {x: x, y: y};
        },
        
        createLoadingMessage: function(){
            this.loading_message = $(document.createElement('div'));
            this.loading_message.addClass('magnifier_loading_message');
            this.loading_message.setStyles({width: this.original_size.width - 2,
                                              height: this.original_size.height - 2,
                                              top: 0,
                                              left: 0,
                                              position:'absolute',
                                              border: '1px solid black',
                                              background: '#ffffff',
                                              color: '#000000',
                                              opacity: 0.65,
                                              textAlign: 'center' ,
                                              fontWeight: 'bold'
                                            });
            this.loading_message.set('text', this.options.loading_text);
            this.small_el.grab(this.loading_message);
            this.loading_message.addEvent('mouseleave', this.removeLoadingMessage.bindWithEvent(this));
        },
        
        removeLoadingMessage: function(){
            if(!$chk(this.loading_message)) return;
            if(this.waiting_for_load) this.waiting_for_load = false;
            this.loading_message.remove();
            this.loading_message = null;
        },
        
        createContainer: function(){
            this.el = $(document.createElement('div'));
            this.el.addClass('magnifier');
            this.small_el = $(document.createElement('div'));
            this.small_el.addClass('magnifier_small');
            this.small_el.setStyles( { position:'relative', 
                                               overflow: 'hidden'
                                             });
            this.small_el.wraps(this.original);
        },
        
        createHighlight: function(){
            if(!$chk(this.highlight_width)) this.determineSizeAndPositioning();
            this.highlight = $(document.createElement('div'));
            this.highlight.addClass('magnifier_highlight');
            this.highlight.setStyles({width: this.highlight_width, 
                                              height: this.highlight_height,
                                              top: 0,
                                              left: 0,
                                              position:'absolute',
                                              border: '1px solid black',
                                              background: '#ffffff',
                                              opacity: 0.4 
                                            });
            this.small_el.grab(this.highlight);
            // add mousemove and mouseleave to highlight as this will obscure the original img
            this.highlight.addEvent('mousemove', this.onMouseMove.bindWithEvent(this));
            this.highlight.addEvent('mouseleave', this.onMouseOut.bindWithEvent(this));
        },
        
        createLarge: function(){
            this.large_wrapper_el = $(document.createElement('div'));
            this.large_wrapper_el.addClass('magnifier_large_wrapper');
            this.large_wrapper_el.setStyles({ 'float': 'left' });
            this.large_el = $(document.createElement('div'));
            this.large_el.addClass('magnifier_large');
            this.large_el.setStyles( { position:'relative', 
                                               overflow: 'hidden',
                                               width: this.options.width,
                                                height: this.options.height 
                                             });
            this.magnified.setStyles({ top: 0, left: 0, position:'absolute' });
            this.large_el.grab(this.magnified);
            this.large_wrapper_el.grab(this.large_el);
            //this.el.grab(this.large_wrapper_el);
            document.body.appendChild(this.large_wrapper_el)
            // position it
            // work out adjustmentof large wrapper taking into account all margins etc 
            var current = this.large_wrapper_el;
            var h_adjustment = 0;
            var v_adjustment = 0;
            while(current){
                if( this.options.center_image ){
                    // position based on the magnified image
                    h_adjustment += 2 * current.getStyle('margin-left').toInt();
                    h_adjustment += 2 * current.getStyle('padding-left').toInt();
                    h_adjustment += 2 * current.getStyle('border-left').toInt();
                    v_adjustment += 2 * current.getStyle('margin-top').toInt();
                    v_adjustment += 2 * current.getStyle('padding-top').toInt();
                    v_adjustment += 2 * current.getStyle('border-top').toInt();
                }else{ 
                    // center based on the wrapper 
                    h_adjustment += current.getStyle('margin-left').toInt();
                    h_adjustment += current.getStyle('margin-right').toInt();
                    h_adjustment += current.getStyle('padding-left').toInt();
                    h_adjustment += current.getStyle('padding-right').toInt();
                    h_adjustment += current.getStyle('border-left').toInt();
                    h_adjustment += current.getStyle('border-right').toInt();
                    v_adjustment += current.getStyle('margin-top').toInt();
                    v_adjustment += current.getStyle('margin-bottom').toInt();
                    v_adjustment += current.getStyle('padding-top').toInt();
                    v_adjustment += current.getStyle('padding-bottom').toInt();
                    v_adjustment += current.getStyle('border-top').toInt();
                    v_adjustment += current.getStyle('border-bottom').toInt();
                }
                current = (current.getChildren().length) ? $(current.getChildren()[0]) : false;
            }
            // horizontal
            switch(this.options.horizontal){
              case 'left':
                  var h_pos = this.original_x - (this.large_wrapper_el.getSize().x + h_adjustment);
                  break;
              case 'center':
                  var h_pos = this.original_x - ( ( ( this.large_wrapper_el.getSize().x + h_adjustment ) - this.original_size.width ) / 2 );
                  break;
              case 'right':
              default:
                  var h_pos = this.original_x + this.original_size.width + h_adjustment;
                  break;
            }
            // vertical
            switch(this.options.vertical){
              case 'top':
                  var v_pos = this.original_y - (this.large_wrapper_el.getSize().y + v_adjustment);
                  break;
              case 'center':
                  var v_pos = this.original_y - ( ( ( this.large_wrapper_el.getSize().y ) - this.original_size.height ) / 2 );
                  break;
              case 'bottom':
              default:
                  var v_pos = this.original_y + this.original_size.height + v_adjustment;
                  break;
            }
            this.large_wrapper_el.setStyles({ position:'absolute', 
                                                          top: v_pos,
                                                          left: h_pos
                                                         });
        }

});