
var Zoomer = function(elementId, imageSrc, ratio){
  this.id = elementId;
  this.imageSrc = imageSrc;
  this.initialized = false;
  this.imgLoaded = false;
  this.element = $(elementId);
  
  this.w = this.element.getWidth();
  this.h = this.element.getHeight();
  this.w2 = this.w * ratio;
  this.h2 = this.h * ratio;

  // Build html structure for magnifier:
  this.magnifier =  new Element('div', { className:'magnifier', style:'display:none;' });
  this.magnifier.appendChild(new Element('div', { className:'magnifier-eye' }));
  this.imgContainer = new Element('div', { className:'magnifier-img' });
  this.imgContainer.innerHTML = '<p style="padding:10px;">Zooming...</p>';
  this.magnifier.appendChild(this.imgContainer);
  document.body.appendChild(this.magnifier);
  
  this.observerFn = null;
  this.onMouseOverFn = this.ObserveZoomer.bind(this);
  Zoomer.addInstance(this);
  Event.observe(this.element, 'mouseover', this.onMouseOverFn);
}

Zoomer.instances = [];

Zoomer.getInstance = function(elementId){
  for(var i=0; i < Zoomer.instances.length; i++){
    if(Zoomer.instances[i].id === elementId){
      return Zoomer.instances[i];
    }
  }
};

Zoomer.addInstance = function(instance){
  var inst = Zoomer.getInstance(instance.id);
  if(inst){ inst.Dispose(); }
  Zoomer.instances.push(instance);
};

Zoomer.prototype = {

  CalculateOffset: function(){
    this.imgOffset = this.element.cumulativeOffset();
    this.imgOffsetX = this.imgOffset.left;
    this.imgOffsetY = this.imgOffset.top;
  },

  OnImageLoad: function(){
    this.imgContainer.removeChild(this.imgContainer.firstChild);
    this.imgContainer.appendChild(this.magnifierImg);
    this.imgLoaded = true;
  },

  ObserveZoomer: function(){
    this.CalculateOffset();
    if(!this.initialized){
      // Load big image:
      this.initialized = true;
      this.magnifierImg = new Image();
      Event.observe(this.magnifierImg, 'load', this.OnImageLoad.bind(this));
      this.magnifierImg.src = this.imageSrc;
      this.magnifierImg.width = this.w2;
      this.magnifierImg.height = this.h2;
      this.magnifierImg.className = 'magnifier-image';
    }
    this.observerFn = this.OnMouseMove.bindAsEventListener(this);
    Event.observe(document, 'mousemove', this.observerFn);
  },

  OnMouseMove: function(event){
    var x = Event.pointerX(event);
    var y = Event.pointerY(event);
    var relativeX = x - this.imgOffsetX;
    var relativeY = y - this.imgOffsetY;
    var x2 = -(relativeX - 25) / this.w * this.w2;
    var y2 = -(relativeY - 25) / this.h * this.h2;
    this.magnifier.style.left = (x - 25) + 'px';
    this.magnifier.style.top = (y - 175) + 'px';
    this.magnifier.show();
    if(this.imgLoaded){
      this.magnifierImg.style.left = x2 + 'px';
      this.magnifierImg.style.top = y2 + 'px';
    }
    if(relativeX < 0 || relativeX > this.w || relativeY < 0 || relativeY > this.h){
      Event.stopObserving(document, 'mousemove', this.observerFn);
      this.magnifier.hide(); 
    }
  },
  
  Dispose: function(){
    // console.log('Disposing... ' + this.id);
    Event.stopObserving(this.element, 'mouseover', this.onMouseOverFn);
    Event.stopObserving(document, 'mousemove', this.observerFn);
    this.element = null;
    this.magnifierImg = null;
    this.magnifier.parentNode.removeChild(this.magnifier);
    this.magnifier = null;
    for(var i=0; i < Zoomer.instances.length; i++){
      if(Zoomer.instances[i] === this){
        Zoomer.instances[i] = null;
        Zoomer.instances.splice(i, 1);
        break;
      }
    }
  }

}
