/**
 * @author 	  Marcel Linnenfelser
 * @copyright SynFlag Online Agentur, Marcel Linnenfelser. All rights reserved.
 * @license   Contributed under the terms of the New BSD License as found in the
 *            license.txt file or under http://www.synflag.com/newbsd.txt.
 */

	
var imagePath = 'images/zoomer/';

/*
 * Wheel thing
 */
var wheelObserver = {
  observers: new Array(),
  addObserver: function () {
    var _args = arguments;
    if (arguments.length == 1) {
      this.observers.push(function (delta) {
        _args[0](this, delta);
      });
    } else if (arguments.length == 2) {
      this.observers.push(function (delta) {
        _args[1].call(_args[0], delta);
      });
    }
  },
  notifyObservers: function (delta) {
    for (var i = 0; i < this.observers.length; i++)
       this.observers[i](delta);
  }
};

function wheel(event){
      var delta = 0;
       if (!event)
             event = window.event;
       if (event.wheelDelta) {
             delta = event.wheelDelta/120;
             if (window.opera)
                   delta = -delta;
       } else if (event.detail) {
             delta = -event.detail/3;
       }
       if (delta)
             wheelObserver.notifyObservers(delta);
       if (event.preventDefault)
            event.preventDefault();
  event.returnValue = false;
}

/**
 * Zoomer class
 * @param {Object} divid
 * @param {Object} images
 * @param {Object} loadingimg
 */  
function SmoothImageZoomer (divid, images, config) {
  
  
  this.init = function (divid, images, config) {
    var _this = this;

    this.factor    = 1;
    
    this.loadingimg = imagePath+"loading.gif";
    this.showZoomRate = false;
    this.showButtons  = false;
    this.buttonOrientation = "vertical";
    this.miniature = null;
    this.mouseTrackerClip = 90; // percent
    this.zoomStep = 10; // percent
    this.maximumZoom = 0; // percent > 100 -> 0 => infinity
    if (config) {
      if (config.loadingImg) {
        this.loadingimg = config.loadingImg;
      }
      if (config.showZoomRate) {
        this.showZoomRate = config.showZoomRate;
      }
      if (config.showButtons) {
        this.showButtons = config.showButtons;
      }
      if (config.buttonOrientation) {
        this.buttonOrientation = config.buttonOrientation;
      }
      if (config.miniature) {
        this.miniature = config.miniature;
      }
      if (config.mouseTrackerClip) {
        this.mouseTrackerClip = config.mouseTrackerClip;
      }
      if (config.zoomStep) {
        this.zoomStep = config.zoomStep;
      }
      if (config.maximumZoom) {
        this.maximumZoom = config.maximumZoom;
      }
    }
    
    wheelObserver.addObserver(this, this.handleWheel);
    
    // Mouse over zoomer
    this.isOver = false;
    this.posX   = this.posY = 0;
    
    this.timer = null;
      
    this.currentImage = 0;
    this.domNode = document.getElementById(divid);
    this.isLoading  = false;
    this.images  = images;
    this.width   = this.getNumberAttribute(this.domNode.style.width);
    this.height  = this.getNumberAttribute(this.domNode.style.height);
    var offset   = this.getRealOffset(this.domNode);
    this.top     = offset.top;
    this.left    = offset.left;
    //this.domNode = document.createElement("div");
    with (this.domNode.style) {
      position = "relative";
      //top      = this.top + "px";
      //left     = this.left + "px"; 
      width    = this.width + "px";
      height   = this.height + "px";
      //border   = "1px solid black";
      overflow = "hidden";
    }
    /*if (document.body)
      document.body.appendChild(this.domNode);
    else
      document.documentElement.appendChild(this.domNode);*/
      
    var innerdiv  = document.createElement("div");
    this.innerdiv = innerdiv;
    
    if (this.showButtons)
      this.domNode.appendChild(this.makeButtons());
    if (this.showZoomRate)
      this.domNode.appendChild(this.makeZoomRate());
    if (this.miniature)
      this.makeMiniature();
    
    this.domNode.onmouseover = function () {
      if (window.addEventListener)
        window.addEventListener('DOMMouseScroll', wheel , false);
      window.onmousewheel = document.onmousewheel = wheel;
      document.onmousemove = function (e) {
        return _this.captureMouse(e);
      }
      _this.isOver = true;
    }
    
    this.domNode.onmouseout = function () {
      if (window.removeEventListener)
        window.removeEventListener('DOMMouseScroll', wheel , false);
      window.onmousewheel = document.onmousewheel = null;
      document.onmousemove = null;
      _this.isOver = false;
    }
    
    this.loadImage(images[0][0], images[1][0], function () {
      var w  = _this.width;
      var h = Math.round(this.height * (w / this.width));
      with (innerdiv.style) {
        position = "absolute";
        width    = w  + "px";
        height   = h + "px";
      }
      var img = document.createElement("img");
      img.width  = w;
      img.height = h;
      img.src=this.src;
      innerdiv.appendChild(img);
      _this.domNode.appendChild(innerdiv);
      _this.img = img;
      _this.images[0][2] = true;
    });

    //dan: sorgt fue groessenanpassung an zoomer-dimension!
    this.onZoomOut();
  }

  this.setOpacity = function(obj, value) {
    obj.style.opacity = value/100;
    obj.style.filter = 'alpha(opacity=' + value + ')';
  }
  
  this.makeMiniature = function () {
    var _this = this;
    var loader = new Image();
    loader.onload = function () {
      var img = document.createElement("img");
      var div = document.createElement("div");
      var clipping = document.createElement("div");
      clipping.bg = document.createElement("div");
      img.src = _this.miniature;
      _this.miniature = div;
      _this.miniatureImage = img;
      _this.clipping = clipping;
      with (div.style) {
        position = "absolute";
        height = loader.height + "px";
        width  = loader.width  + "px";
        left   = (_this.width  - loader.width - 1)  + "px";
        top    = (_this.height - loader.height - 1) + "px";
        border = "1px solid black";
        zIndex = 99;
        overflow = "hidden";
      }
      with (clipping.style) {
        position = "absolute";
        height = (loader.height - 2)  + "px";
        width  = (loader.width - 2)   + "px";
        left   = "0px";
        top    = "0px";
        border = "1px solid red";
        overflow = "hidden"; // to allow ie height up to 0
        zIndex = 99;
      }
      with (clipping.bg.style) {
        position = "absolute";
        height = (loader.height - 2)  + "px";
        width  = (loader.width - 2)   + "px";
        left   = "0px";
        top    = "0px";
        overflow = "hidden"; // to allow ie height up to 0
        backgroundColor = "red";
      }
      $(clipping.bg).fadeTo(0, 0.3);
      with (img) {
        height = loader.height;
        width  = loader.width;
      }
      if (!$.browser.msie)
        clipping.appendChild(clipping.bg);
      div.appendChild(img);
      div.appendChild(clipping);
      _this.domNode.appendChild(div);
    };
    loader.src = this.miniature;
  }
  
  this.makeClipping = function () {
    if (this.clipping) {
      with (this.clipping.style) {
        var h = Math.round(this.miniatureImage.height / this.factor) - 2;
        var w = Math.round(this.miniatureImage.width / this.factor) - 2;
        var t = Math.ceil(
              Math.abs(this.getNumberAttribute(this.innerdiv.style.top)) 
              / this.getNumberAttribute(this.innerdiv.style.width)
                * this.miniatureImage.width);
        if (t != 0 && t + h + 2 > this.miniatureImage.height)
          t--;
        var l = Math.ceil(
              Math.abs(this.getNumberAttribute(this.innerdiv.style.left)) 
              / this.getNumberAttribute(this.innerdiv.style.height)
                * this.miniatureImage.height);
        if (l != 0 && l + w  + 2 > this.miniatureImage.width)
          l--;
        if (w<0)
          w = 0;
        if (h<0)
          h = 0;
        height = parseInt(h) + "px";
        width  = parseInt(w) + "px";
        top    = t + "px";
        left   = l + "px";
      }
    }
  }
  
  this.makeButtons = function () {
    var _this = this;
    var zoomdiv   = document.createElement("div");
    with (zoomdiv.style) {
      position = "absolute";
      top      = "0px";
      left     = "0px";
      zIndex   = 99;
    }
    var aZoomIn  = document.createElement("a");
    aZoomIn.onmousedown = function () {
      _this.doZoomIn();
      return false;
    }
    aZoomIn.onmouseup = function () {
      window.clearInterval(_this.timer);
      return false;
    }
    aZoomIn.href = "#";
    if (this.buttonOrientation == "vertical") {
      aZoomIn.innerHTML = '<img src="'+imagePath+'lupe_plus.gif" style="display:block" border="0"/>';
    } else {
      aZoomIn.innerHTML = '<img src="'+imagePath+'lupe_plus.gif" border="0"/>';
    }
    var aZoomOut = document.createElement("a");
    aZoomOut.onmousedown = function () {
      _this.doZoomOut();
      return false;
    }
    aZoomOut.onmouseup = function () {
      window.clearInterval(_this.timer);
      return false;
    }
    aZoomOut.href = "#";
    aZoomOut.innerHTML = '<img src="'+imagePath+'lupe_minus.gif" border="0"/>';
    zoomdiv.appendChild(aZoomIn);
    zoomdiv.appendChild(aZoomOut);
    return zoomdiv;
  }
  
  this.makeZoomRate = function () {
    var zoomRate   = document.createElement("div");
    with (zoomRate.style) {
      position = "absolute";
      top      = "-1px";
      left     = (this.width - 49) + "px";
      width    = "50px";
      textAlign = "center";
      zIndex   = 99;
      backgroundColor = "white";
      paddingTop    = "2px";
      paddingBottom = "2px";
      border   = "1px solid black";
      fontFamily = "Arial, Helvetica";
      fontSize   = "12px";
      color      = 'black';
    }
    zoomRate.innerHTML = "100%";
    this.zoomRate = zoomRate;
    return zoomRate;
  }
  
  this.handleWheel = function (delta) {
    if (!this.isOver || this.isLoading)
      return;
        if (delta < 0)
      this.onZoomOut();
        else
      this.onZoomIn();
  }
  
  this.loadImage = function(url, preloadUrl, callback) {
    var loader = new Image();
    var _this = this; 
    this.showLoading(true);
    this.isLoading = true;
    loader.onload = function () { 
      _this.isLoading = false; 
      _this.showLoading(false); 
      _this.currentImageSize = {
        height: this.height,
        width:  this.width
      };
      if (preloadUrl) {
        var preLoader = new Image();
        preLoader.src = preloadUrl;
      }
      callback.apply(loader, []); 
      loader.onload=function(){};
    };
    loader.src = url;
  }
  
  this.showLoading = function (bool) {
    if (bool) {
      this.loading     = document.createElement("img");
      this.loading.src = this.loadingimg;
      with (this.loading.style) {
        position = "absolute";
        top      = Math.round(this.height / 2 - 16) + "px";
        left     = Math.round(this.width  / 2 - 16) + "px";
        zIndex   = 99;
        backgroundColor = "white";
        padding  = "15px";
      }
      this.domNode.appendChild(this.loading);
    } else {
      if (this.loading) {
        this.domNode.removeChild(this.loading);
      }
    }
  }
  
  this.captureMouse = function (e) {
    var posx = 0;
    var posy = 0;
    if (!e) var e = window.event;
    if (e.pageX || e.pageY) {
      posx = e.pageX;
      posy = e.pageY;
    } else if (e.clientX || e.clientY) {
      posx = e.clientX + document.body.scrollLeft
        + document.documentElement.scrollLeft;
      posy = e.clientY + document.body.scrollTop
        + document.documentElement.scrollTop;
    }
    this.posX = posx;
    this.posY = posy;
    this.onMouseMove(posx, posy);
      return true;
  }
  
  this.getRealOffset = function (obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) {
      curleft = obj.offsetLeft
      curtop = obj.offsetTop
      while (obj = obj.offsetParent) {
        curleft += obj.offsetLeft
        curtop += obj.offsetTop
      }
    }
    return {left: curleft, top: curtop};
  }        
  
  this.onMouseMove = function (posx, posy) {
    if (this.isLoading)
      return;
    var offset = this.getRealOffset(this.domNode);
    var clip = this.mouseTrackerClip / 100;
    var pH = (this.height -  (this.height * clip)) / 2;
    var pW = (this.width  -  (this.width  * clip)) / 2;
    posx = posx - offset.left - pW;
    posy = posy - offset.top  - pH;
    if (posx < 0)
      posx = 0;
    if (posy < 0)
      posy = 0;
    var h = this.height - (pH * 2);
    var w = this.width  - (pW * 2);
    var idHeight = this.getNumberAttribute(this.innerdiv.style.height);
    var idWidth  = this.getNumberAttribute(this.innerdiv.style.width);
    with (this.innerdiv.style) {
      var t = l = 0;
      // the 1 shall fix a possible rounding error, where a picture at 100% 
      // follows the mouse because of one 
      if (idWidth > this.width && idHeight > this.height + 1) {
        t = Math.round((((idHeight - (2 * pH) - h) / h) * posy));
        if (t > idHeight - this.height)
          t = idHeight - this.height;
        l = Math.round((((idWidth  - (2 * pW) - w) / w)  * posx));
        if (l > idWidth - this.width)
          l = idWidth - this.width;
      }
      top  = "-" + t + "px";
      left = "-" + l + "px";
    }
    this.makeClipping();
  }
  
  /*this.onMouseMove_old = function (posx, posy) {
    if (this.isLoading)
      return;
    var offset = this.getRealOffset(this.domNode);
    var idHeight = this.getNumberAttribute(this.innerdiv.style.height);
    var idWidth  = this.getNumberAttribute(this.innerdiv.style.width);
    with (this.innerdiv.style) {
      var t = l = 0;
      // the 1 shall fix a possible rounding error, where a picture at 100% 
      // follows the mouse because of one 
      if (idWidth > this.width && idHeight > this.height + 1) {
        t = Math.round(((idHeight - this.height) / this.height) * (posy - offset.top));
        if (t > idHeight - this.height) t = idHeight - this.height;
        l = Math.round(((idWidth  - this.width)  / this.width)  * (posx - offset.left));
        if (l > idWidth - this.width) l = idWidth - this.width;
      }
      top  = "-" + t + "px";
      left = "-" + l + "px";
    }
    this.makeClipping();
  }*/
  
  this.getNumberAttribute = function (value) {
    return parseInt(this.substr(value, 0, -2));
  }
  
  this.substr = function (str, start, end) {
    return str.substring(start, (str.length+end)%str.length);
  }
  
  this.perCent = function (width) {
    this.factor = width / this.width
    return Math.round(this.factor * 100);
  }
  
  this.doZoomIn = function (){
    var _this = this;
    this.timer = window.setInterval(function () {
      _this.onZoomIn();
    }, 150);
  }
  
  this.doZoomOut = function (){
    var _this = this;
    this.timer = window.setInterval(function () {
      _this.onZoomOut();
    }, 150);
  }
  
  this.onZoomIn = function () {
    if (this.isLoading || (this.maximumZoom != 0 && Math.round(this.factor * 100  * (1 + this.zoomStep/100)) > this.maximumZoom))
      return;
    var width  = Math.floor(this.getNumberAttribute(this.innerdiv.style.width) * (1 + this.zoomStep/100));
    var height = this.currentImageSize.height * (width / this.currentImageSize.width);
    this.innerdiv.style.height = height + "px";
    this.innerdiv.style.width =  width  + "px";
    this.onMouseMove(this.posX, this.posY);
    this.img.height = height;
    this.img.width  = width;
    this.zoomRate.innerHTML = this.perCent(width) + "%";
    this.makeClipping();
    if (this.currentImage < this.images.length - 1 && width >= this.images[this.currentImage+1][1]) {
      this.currentImage++;
      this.loadCurrentImage();
    } 
  }

  this.onZoomOut = function () {
    if (this.isLoading)
      return;
    var width  = Math.ceil(this.getNumberAttribute(this.innerdiv.style.width) / (1 + this.zoomStep/100));
    if (this.width > width)
      width = this.width;
    var height = this.currentImageSize.height * (width / this.currentImageSize.width);
    this.innerdiv.style.height = height + "px";
    this.innerdiv.style.width =  width  + "px";
    this.onMouseMove(this.posX, this.posY);
    this.img.height = height;
    this.img.width  = width;
    this.zoomRate.innerHTML = this.perCent(width) + "%";
    this.makeClipping();
    if (this.currentImage > 0 && this.images[this.currentImage][1] >= width) {
      this.currentImage--;
      this.loadCurrentImage();
    } 
  }
  
  this.loadCurrentImage = function () {
      var _this = this;
      var preloadUrl = this.currentImage + 1 < this.images.length ? this.images[this.currentImage+1][0] : "";
      if (this.images[this.currentImage][2]) {
        this.img.src = this.images[this.currentImage][0];
      } else {
        this.loadImage(this.images[this.currentImage][0], preloadUrl, function () {
          _this.images[_this.currentImage][2] = true;
          _this.img.src = _this.images[_this.currentImage][0];
        });
      }
  }

  this.init(divid, images, config);
}
      

