// Image Rotation with <canvas>

function sawFunc(a)
{
	var PI = Math.PI;
	var PI2 = PI / 2;

	// make sure a is within 0 to PI
	a = a % PI;

	if (a < 0) a += PI;

	return a < PI2 ? (a / PI2) : ((PI-a)/PI2);
}

function easeInEaseOut(t)
{
	var t2 = t * t;
	return 3 * t2 - 2 * t * t2;
}

function ImageRotator(el, src, w, h)
{
	this.element = el;
	this.toolBar = el.getElementsByTagName("div")[0];
	this.canvas = el.getElementsByTagName("canvas")[0];
	var images = el.getElementsByTagName("img");
	this.image = images[images.length - 1];
	var btns = el.getElementsByTagName("button");
	this.btnCw = btns[0];
	this.btnCcw = btns[1];
	var self = this;

	this.btnCcw.onclick = function()
	{
		self.rotateCcw();
	};

	this.btnCw.onclick = function()
	{
		self.rotateCw();
	};

	this.image.onload = function(e)
	{
		self.onImageLoad(e);
	};

	this.image.onerror = function(e)
	{
		self.onImageError(e);
	};

	this.image.onabort = function(e)
	{
		self.onImageAbort(e);
	};

	var onResize = function()
	{
		self.layout();
	};

	var onLoad = function()
	{
		self.onWindowLoad();
	};

	this.setImage(src, w, h);
	this.layout();

	if (window.addEventListener)
	{
		window.addEventListener("resize", onResize, false);
		window.addEventListener("load", onLoad, false);
	}
	else if (window.attachEvent)
	{
		window.attachEvent("onresize", onResize);
		window.attachEvent("onload", onLoad);
	}
}

ImageRotator.prototype =
{
	getLoaded: function()
	{
		//return this.imageLoaded && this.windowLoaded;
		return true;
	},

	setImage: function(src, w, h)
	{
		this.imageLoaded = false;
		this.image.src = src;
		this.imageWidth = w;
		this.imageHeight = h;
	},

	layout: function()
	{
		var PI2 = Math.PI / 2;
		var h = this.element.clientHeight;
		var w = this.element.clientWidth;
		var th = this.toolBar.offsetHeight;

		// Sometimes this is 0, so set it to something, thus not ending up negative
		if (w == 0) w = 512;
		if (h == 0) h = 384;

		h -= this.toolBar.offsetHeight;

		if (!this.ctx || !this.getLoaded())
		{
			this.btnCw.disabled = true;
			this.btnCcw.disabled = true;
			this.canvas.style.display = "none";
			this.image.style.display = "block";
			var ratio = Math.min(w / this.imageWidth, h / this.imageHeight, 1);
			var imgW = this.imageWidth * ratio;
			var imgH = this.imageHeight * ratio;
			var y = th + (h - imgH) / 2;
			var x = (w - imgW) / 2;
			this.image.style.left = Math.round(x) + "px";
			this.image.style.top = Math.round(y) + "px";
			this.image.style.width = Math.round(imgW) + "px";
			this.image.style.height = Math.round(imgH) + "px";
		}
		else
		{
			this.btnCw.disabled = this.isAnimating_;
			this.btnCcw.disabled = this.isAnimating_;
			this.canvas.style.display = "block";
			this.image.style.display = "none";

			this.canvas.style.left = 0 + "px";
			this.canvas.style.top = th + "px";
			this.canvas.style.width = w + "px";
			this.canvas.width = w;
			this.canvas.style.height = h + "px";
			this.canvas.height = h;

			this.ctx.save();
			this.ctx.clearRect(0, 0, w, h);
			this.ctx.translate(w / 2, h / 2);
			this.ctx.rotate(this.rotation);
			// 0 -> 1, sin(0) = 0
			// PI / 2 -> H / W, sin(PI/2) = 1

			// sin(PI/2) = 1 -> limit factor is w and imgH

			var iw = this.imageWidth;
			var ih = this.imageHeight;
			var scale;

			if (iw <= w && iw <= h && ih <= h && ih <= w)
			{
				scale = 1;
			}
			else
			{
				var sinr = sawFunc(this.rotation);
				var cosr = sawFunc(this.rotation + PI2);
				var ratio1 = sinr * Math.min(w / ih, h / iw);
				var ratio2 = cosr * Math.min(w / iw, h / ih);
				var ratio = Math.min(1, ratio1 + ratio2);
				scale = ratio;
			}

			this.ctx.scale(scale, scale);
			this.ctx.translate(-iw / 2, -ih / 2);
			this.ctx.drawImage(this.image, 0, 0, iw, ih);
			this.ctx.restore();
		}
	},

	rotation: 0,
	animationDuration: 240,

	rotateCcw: function()
	{
		if (this.isAnimating_) return;

		this.startTime_ = (new Date).valueOf();
		this.currentAngle_ = this.rotation;
		this.deltaAngle_ = Math.PI / 2;
		this.isAnimating_ = true;
		this.animCounter_ = 0;
		this.rotate_();
	},

	rotateCw: function()
	{
		if (this.isAnimating_) return;

		this.startTime_ = (new Date).valueOf();
		this.currentAngle_ = this.rotation;
		this.deltaAngle_ = -Math.PI / 2;
		this.isAnimating_ = true;
		this.animCounter_ = 0;
		this.rotate_();
	},

	rotate_: function()
	{
		if (!this.isAnimating_) return;

		var t = easeInEaseOut(Math.min(1, (new Date - this.startTime_) / this.animationDuration));
		this.rotation = t * this.deltaAngle_ + this.currentAngle_;

		if (t < 1)
		{
			var self = this;
			window.setTimeout(function () { self.rotate_(); }, 10);
		}
		else
		{
			this.isAnimating_ = false;
		}

		this.layout();
	},

	onImageLoad: function(e)
	{
		this.imageLoaded = true;
		this.initCanvas();
	},

	onImageError: function(e)
	{
		this.imageLoaded = false;
	},

	onImageAbort: function(e)
	{
		this.imageLoaded = false;
	},

	onWindowLoad: function(e)
	{
		this.windowLoaded = true;
		this.initCanvas();
	},

	initCanvas: function()
	{
		if (this.ctx && this.getLoaded()) return;

		// IE recreates the element?
		this.canvas = this.element.getElementsByTagName("canvas")[0];
		this.ctx = this.canvas.getContext("2d");

		if (!this.ctx) return;

		this.layout();
	}
};

//


