function roundAt(x, n) {
	// test if browser supports method
	if (x.toFixed) return x.toFixed(n);

	// browser does not support method
	if (n < 1 || n > 14) return false;
	var e = Math.pow(10, n);
	var k = (Math.round(x * e) / e).toString();
	if (k.indexOf('.') == -1) k += '.';
	k += e.toString().substring(1);
	return k.substring(0, k.indexOf('.') + n+1);
}

function pad(number, length) {
	var str = '' + number;
	while (str.length < length)
		str = '0' + str;
	return str;
}

/* Copyright (c) 2008 Peter Sarnacki (drogomir.com) Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php */

var UploadProgressMethods = {
	uploadProgress: function(element, options) {
		options == options || {};
		options = Object.extend({
			interval: 2000,
			progressBar: "progressBar",
			progressInfo: "progressInfo",
			progressReceived: "progressReceived",
			progressSize: "progressSize",
			progressSpeed: "progressSpeed",
			progressLeft: "progressLeft",
			progressUrl: "/progress",
			progressType: "increase",
			start: function() {},
			uploading: function() {},
			complete: function() {},
			success: function() {},
			error: function() {},
			uploadProgressPath: 'prototype.js',
			prototypePath: 'uploadProgress.js',
            timer: ""
		}, options);

		/* tried to add iframe after submit (to not always load it) but it won't work.
		safari can't get scripts properly while submitting files */
		if(Prototype.Browser.WebKit && top.document == document) {
			/* iframe to send ajax requests in safari
			thanks to Michele Finotto for idea */
			iframe = document.createElement('iframe');
			iframe.name = "progressFrame";
			$(iframe).setStyle({width: '0', height: '0', position: 'absolute', top: '-3000px'});
			document.body.appendChild(iframe);

			var d = iframe.contentWindow.document;
			d.open();
			/* weird - safari won't load scripts without this lines... */
			d.write('<html><head></head><body></body></html>');
			d.close();

			var b = d.body;
			var s = d.createElement('script');
			s.src = options.prototypePath;
			/* must be sure that jquery is loaded */
			s.onload = function() {
				var s1 = d.createElement('script');
				s1.src = options.uploadProgressPath;
				b.appendChild(s1);
			}
			b.appendChild(s);
		}

		Event.observe(element, 'submit', function() {
			var uuid = "";
			for (i = 0; i < 32; i++) { uuid += Math.floor(Math.random() * 16).toString(16); }

			options.uuid = uuid;
			/* start callback */
			options.start();

			/* patch the form-action tag to include the progress-id
            if X-Progress-ID has been already added just replace it */
			if(old_id = /X-Progress-ID=([^&]+)/.exec($(this).readAttribute("action"))) {
				var action = $(this).readAttribute("action").replace(old_id[1], uuid);
				$(this).writeAttribute("action", action);
			} else {
				$(this).writeAttribute("action", $(this).readAttribute("action") + "?X-Progress-ID=" + uuid);
			}
			var uploadProgress = Prototype.Browser.WebKit ? progressFrame.Prototype.uploadProgress : Prototype.uploadProgress;
			options.timer = window.setInterval(function() { uploadProgress(this, options) }, options.interval);
		});
	}
};

Element.addMethods(UploadProgressMethods);

PrototypeUploadProgressMethods = {
	uploadProgress: function(element, options) {
		new Ajax.Request(options.progressUrl, {
			method: 'get',
			parameters: 'X-Progress-ID='+ options.uuid,
			onSuccess: function(xhr){
				var upload = xhr.responseText.evalJSON();

				upload.percents = Math.floor((upload.received / upload.size)*100);
				if (upload.state == 'uploading') {

					var bar = Prototype.Browser.WebKit ? parent.document.getElementById(options.progressBar) : $(options.progressBar);
					var info = Prototype.Browser.WebKit ? parent.document.getElementById(options.progressInfo) : $(options.progressInfo);
					var rec = Prototype.Browser.WebKit ? parent.document.getElementById(options.progressReceived) : $(options.progressReceived);
					var size = Prototype.Browser.WebKit ? parent.document.getElementById(options.progressSize) : $(options.progressSize);
					var speed = Prototype.Browser.WebKit ? parent.document.getElementById(options.progressSpeed) : $(options.progressSpeed);
					var left = Prototype.Browser.WebKit ? parent.document.getElementById(options.progressLeft) : $(options.progressLeft);

					if (info != null) info.innerHTML = Math.floor(upload.percents) + '%';
					if (rec != null) rec.innerHTML = roundAt(upload.received / 1048576, 2);
					if (size != null) size.innerHTML = roundAt(upload.size / 1048576, 2);
					if (speed != null) speed.innerHTML = roundAt(upload.speed / 1024, 2);

					if (left != null && upload.speed > 0) {
						var timeLeft = Math.floor((upload.size-upload.received)/upload.speed);
						var secs = (timeLeft % 60);
						var mins = Math.floor((timeLeft / 60) % 60);
						var hours = Math.min(Math.floor(timeLeft / 3600), 99);
						left.innerHTML = pad(hours, 2) + ":" + pad(mins, 2) + ":" + pad(secs, 2);
					}

					if (options.progressType == 'increase') {
						bar.setStyle({width: Math.floor(upload.percents) + '%'});
					} else {
						bar.setStyle({width: (100-Math.floor(upload.percents)) + '%'});
					}

					options.uploading(upload);
				}

				/* we are done, stop the interval */
				if (upload.state == 'done' || upload.state == 'error') {
					window.clearTimeout(options.timer);
					options.complete(upload);
				}

				if (upload.state == 'done') {
					options.success(upload);
				}

				if (upload.state == 'error') {
					options.error(upload);
				}
			}
		});
	}
};

Object.extend(Prototype, PrototypeUploadProgressMethods);