/*
imageZoom v1.0
==============
Author: Gonzalo Pérez de la Ossa

Date: 26/10/2009

Description: a prototype plugin that generates a zoomable interface for an image

Usage:
Load by calling: imageZoom.init('divId', maxZoomLevel)
The file naming convention is importat: all files belonging to a single image must be in the form: imageName_Z.ext, where Z is the zoom level, and must be sequential, i.e.: myImage_1.jpg, myImage_2.jpg, myImage_3.jpg
*/
var imageZoom = {

  init: function(divId, maxZoom) {
	div = $(divId);

	// Get some info
	img = div.select('img')[0];

	// Wait until the image is loaded
	if (!img.complete) {
		// Wait, image is not fully loaded
		setTimeout(function(){imageZoom.init(divId, maxZoom)}, 500);
		return;
	}

	// Initialize img draggable object
	img.maxZoom = maxZoom;
	imgUnderscorePos = img.src.lastIndexOf('_');
	imgDotPos = img.src.lastIndexOf('.');
	img.path = img.src.substring(0, imgUnderscorePos + 1);
	img.ext = img.src.substr(imgDotPos); // includes .
	img.zoom = parseInt(img.src.substr(imgUnderscorePos + 1, imgDotPos));
	imgDimensions = img.getDimensions();
	img.screenWidth = img.currWidth = imgDimensions.width;
	img.screenHeight = img.currHeight = imgDimensions.height;
	img.setStyle({
	  'left' : 0,
	  'top' : 0
	});

	// Create screen container
	var screenDiv = new Element('div');
	screenDiv.setStyle({
	  'width' : imgDimensions.width + "px",
	  'height' : imgDimensions.height + "px",
	  'overflow' : "hidden",
	  'position' : "relative"
	});

	// Create wait div
	var waitDiv = new Element('div');
	waitDiv.setStyle({
	  'width' : imgDimensions.width + "px",
	  'height' : imgDimensions.height + "px",
	  'background' : "url('/images/test/image_zoom_wait.gif') 50% 50% no-repeat #fff",
	  'opacity' : 0.8,
	  'position' : "absolute",
	  'left' : 0,
	  'top' : 0,
	  'display': "none"
	});
	img.waitDiv = waitDiv;

	// Put the image and the wait div in the screen container
	screenDiv.appendChild(img);
	screenDiv.appendChild(waitDiv);

	// Make draggable
	new Draggable(img, {
	  onDrag: function(obj, evt) {
		if (obj.element.zoom > 1) {
		  obj.element.setStyle({'cursor':"move"});
		}
	  },
	  onEnd: function(obj, evt) {
		obj.element.setStyle({'cursor':"default"});
	  },
	  snap: function(x, y, obj) {
		// TOTHINK: don't get dimensions again? They already are in img object, but they might be null...
		imgDimensions = obj.element.getDimensions();
		minX = img.screenWidth - imgDimensions.width;
		minY = img.screenHeight - imgDimensions.height;
		return[
		  x>0 ? 0 : (x < minX ? minX : x ),
		  y>0 ? 0 : (y < minY ? minY : y )
		  ];
	  }
	});

	// Add to main div
	div.appendChild(screenDiv);

	// Create controls
	var buttons = new Element('div');
	buttons.addClassName("buttons");

	// - Enlarge
	var enlarge = new Element('span').update("[+]");
	enlarge.addClassName("enlarge");
	Event.observe(enlarge, 'click', function() {
	  if (this.zoom < this.maxZoom) {
		this.zoom++;
		this.writeAttribute('src', this.path + this.zoom + this.ext);
		imageZoom.loadNewSize(this);
	  }
	}.bindAsEventListener(img));
	buttons.appendChild(enlarge);

	// - Reduce
	var reduce = new Element('span').update("[-]");
	reduce.addClassName("reduce");
	Event.observe(reduce, 'click', function() {
	  if (this.zoom > 1) {
		this.zoom--;
		this.writeAttribute('src', this.path + this.zoom + this.ext);
		imageZoom.loadNewSize(this);
	  }
	}.bindAsEventListener(img));
	buttons.appendChild(reduce);

	// - Zoom scale
	var zoomScale = new Element('ul');
	zoomScale.addClassName("zoomScale");
	var tmpLi = new Array(maxZoom);
	for (var i=maxZoom ; i>=1 ; i--) {
	  tmpLi[i-1] = new Element('li').update(i);
	  if (i == img.zoom) tmpLi[i-1].addClassName("selected");
	  tmpLi[i-1].zoomLevel = i;
	  tmpLi[i-1].hImg = img;
	  tmpLi[i-1].observe('click', function(){
		this.hImg.zoom = this.zoomLevel;
		this.hImg.writeAttribute('src', this.hImg.path + this.hImg.zoom + this.hImg.ext);
		imageZoom.loadNewSize(this.hImg);
	  }.bindAsEventListener(tmpLi[i-1]));
	  zoomScale.appendChild(tmpLi[i-1]);
	}
	buttons.appendChild(zoomScale);
	img.hZoomScale = zoomScale;

	// Add controls div
	div.appendChild(buttons);

	// Preload other zoom levels
	imageZoom.preloadZoomLevel(img.zoom + 1, img, null);
  },

  loadNewSize: function(img) {
	img.ready = false;
	img.waitDiv.show();
	imgDimensions = img.getDimensions();
	if (img.currWidth == imgDimensions.width && img.currHeight == imgDimensions.height) {
	  setTimeout(function(){imageZoom.loadNewSize(img)}, 50);
	}
	else {
	  // Update zoomScale
	  liArr = img.hZoomScale.select("li");
	  for (var i=0, l=liArr.length ; i<l ; i++) {
		if (liArr[i].zoomLevel == img.zoom) liArr[i].addClassName("selected");
		else liArr[i].removeClassName("selected");
	  }


	  // Work out new position
	  currX = parseInt(img.style.left);
	  if (currX == 0) percentageX = 0;
	  else percentageX = Math.abs(currX)/(img.currWidth - img.screenWidth);
	  currY = parseInt(img.style.top);
	  if (currY == 0) percentageY = 0;
	  else percentageY = Math.abs(currY)/(img.currHeight - img.screenHeight);

	  // Update new image and hide wait div
	  img.style.left = "-" + (imgDimensions.width - img.screenWidth) * percentageX + "px";
	  img.style.top = "-" + (imgDimensions.height - img.screenHeight) * percentageY + "px";
	  img.currWidth = imgDimensions.width;
	  img.currHeight = imgDimensions.height;
	  img.ready = true;
	  img.waitDiv.hide();
	}
  },

  preloadZoomLevel: function(currZoom, img, tmpImg) {
	if (currZoom > img.maxZoom) {
	  return; // done!
	}

	if (tmpImg) {
	  if (tmpImg.complete) {
		imageZoom.preloadZoomLevel(currZoom + 1, img, null);
	  }
	  else {
		setTimeout(function() {imageZoom.preloadZoomLevel(currZoom, img, tmpImg)}, 1000);
	  }
	}
	else {
	  tmpImg = new Image();
	  tmpImg.src = img.path + currZoom + img.ext;
	  imageZoom.preloadZoomLevel(currZoom, img, tmpImg);
	}
  }
}