(function($){

var _window = document;

$.fn.fitinto = function(container){
 if (!this.length) return false;// selector called with returned nothing
 if (!container)
	container = this.closest("[display=block],[display=inline-block]");
 this.data("fitinto-data", {
	container: container,
	width: this.width(),
	height: this.height()
 });
 //console.dir(this.data("fitinto-data"));
 this.zoom_to_fit();
 return true;
}


var pan = function(e, _this){
 e.preventDefault();
 var D = _this.data("fitinto-data");
 var _o = D.container.offset();
 //console.info("x from "+D.offsetX+" to "+e.clientX+", y from "+D.offsetY+" to "+e.clientY);
 var x_move = D.offsetX - e.clientX;
 var y_move = D.offsetY - e.clientY;
 //console.info("x change "+x_move+", y change "+y_move);
 D.offsetX = e.clientX;
 D.offsetY = e.clientY;
 D.x = Math.max(Math.min(D.x + x_move, D.width - D.container.width()), 0)
 D.y = Math.max(Math.min(D.y + y_move, D.height - D.container.height()), 0);
 if (isNaN(D.x)) D.x = 0; if (isNaN(D.y)) D.y = 0;// ie workaround
 _this.css({ top: "-"+D.y+"px", left: "-"+D.x+"px" });
 // event handling
 var _release = function(){
	$(_window).unbind('mousemove.panning');
	_this.removeClass("panning");
 };
 $(_window).one('mouseup', _release);
 //$(this).one('mouseout', _release);
}


$.fn.zoom_to_fit = function(e){
 if (e) e.preventDefault();
 var D = this.data("fitinto-data");
 var _h = D.container.innerHeight();
 var _w = D.container.innerWidth();
 var h_ratio = D.height / _h;
 var w_ratio = D.width / _w;
 if (h_ratio > 1 || w_ratio > 1) {
	var scale_by = (h_ratio > w_ratio) ? h_ratio : w_ratio;
	D.scaling = scale_by;
	this.height(parseInt(D.height / scale_by));
	this.width(parseInt(D.width / scale_by));
 }
 delete D.x;
 delete D.y;
 delete D.offsetX;
 delete D.offsetY;
 this.css({ top: 0, left: 0 });
 this.removeClass("zoomed-out").addClass("zoomed-to-fit");
 D.container.removeClass("zoomed-out").addClass("zoomed-to-fit");
 // event handling
 var _this = this;
 this.one('click', function(e){ return _this.zoom_out(e) });
 this.unbind('mousedown.zoom-out');
 $(window).unbind('resize.zoom-out');
 var _resize_pending = null;
 $(window).one('resize.zoom-to-fit', function(){
	if (_resize_pending) clearTimeout(_resize_pending);
	_resize_pending = setTimeout(function(){ _this.zoom_to_fit() }, 15);
 });
}


$.fn.zoom_out = function(e){
 var D = this.data("fitinto-data");
 if (e) {
	e.preventDefault();
	var _o = this.offset();
	var _x = e.pageX - _o.left;
	var _y = e.pageY - _o.top;
	var _view_width = D.container.width();
	var _view_height = D.container.height();
	var x = Math.max((_x * D.scaling) - (_view_width / 2), 0);
	x = Math.min(x, D.width - _view_width);
	var y = Math.max((_y * D.scaling) - (_view_height / 2), 0);
	y = Math.min(y, D.height - _view_height);
	D.x = x;
	D.y = y;
 }
 this.height(D.height);
 this.width(D.width);
 if (!isNaN(D.x) && !isNaN(D.y))// if above: offset calced wrong
 	this.css({ top: (-1*parseInt(y))+"px", left: (-1*parseInt(x))+"px" });
 // just prepending "-" can break w/ --# on ie
 delete D.scaling;
 this.removeClass("zoomed-to-fit").addClass("zoomed-out");
 D.container.removeClass("zoomed-to-fit").addClass("zoomed-out");
 // event handling
 var _this = this;
 //this.one('click', function(e){ return _this.zoom_to_fit(e) });
 this.bind('mousedown.zoom-out', function(e){
	e.preventDefault();
	D.offsetX = e.clientX;
	D.offsetY = e.clientY;
	_this.addClass("panning");
	$(_window).bind('mousemove.panning', function(e){
		pan(e, _this);
	});
	return false;
 });
 $(window).unbind('resize.zoom-to-fit');
 var _resize_pending = null;
 $(window).bind('resize.zoom-out', function(){
	if (_resize_pending) clearTimeout(_resize_pending);
	_resize_pending = setTimeout(function(){
		D.x = Math.min(D.x, D.width - D.container.width());
		D.y = Math.min(D.y, D.height - D.container.height());
		if (isNaN(D.x)) D.x = 0; if (isNaN(D.y)) D.y = 0;// ie workaround
		_this.css({ top: "-"+D.y+"px", left: "-"+D.x+"px" });
	}, 15);
 });
}


})(jQuery);
