var AjaxForm = Class.create();

Object.extend(AjaxForm.prototype, {
	initialize : function(_formContainerId, _formId, _url, _previewContainerId, _previewUrl, _upload, _traceUrl, _tracerContainerId, _callback /*{onStart(), onFinish()}*/) {
		this.container = $(_formContainerId);
		this.tracerContainer = $(_tracerContainerId);
		this.form = document.forms[_formId];
		this.url = _url;
		this.upload = _upload;
		this.traceUrl = _traceUrl;
		this.previewContainer = $(_previewContainerId);
		this.previewUrl = _previewUrl;
		this.callback = _callback ? _callback : {onStart : function() {} , onFinish : function() {}};

		this.sendForm();
	},

	postprocess : function(o) {
		this.container.innerHTML = o.responseText;
		this.callback.onFinish();
		o.responseText.evalScripts();

		YAHOO.util.Connect.asyncRequest('GET', this.previewUrl, {
			success: function(o){
				o.argument[0].previewContainer.innerHTML = o.responseText;
				o.responseText.evalScripts();
			},
			argument: [o.argument[0]]
		});
	},

	sendForm : function() {
		if(this.upload) {
			this.tracer = new UploadTracer(this.traceUrl, this.tracerContainer.id);
		}

		var callback = {
			success : function(o) {
				o.argument[0].postprocess(o);
			},
			upload : function(o) {
				o.argument[0].form.action = '';
				o.argument[0].form.target = '';
				o.argument[0].postprocess(o);
			},
			failure : function(o) {
				o.argument[0].container.innerHTML += "We are unable to process request at this time. Try again later.";
				o.argument[0].callback.onFinish();
			},
			argument : [this]
		};

		YAHOO.util.Connect.setForm(this.form, this.upload);

		var transaction = YAHOO.util.Connect.asyncRequest('POST', this.url, callback);
		this.callback.onStart();
	}
});


var UploadTracer = Class.create();

Object.extend(UploadTracer.prototype, {
	initialize : function(_url, _containerId) {
		this.url = _url;
		this.container = $(_containerId);

		this.state = { bytesRead : 0, bytesTotal : 0};

		this.pending = false;
		this.probing = true;

		this.render();
		this.show();

		//this brings a small memory leakage on a page when used many times.
		setTimeout(this.probe.bind(this), 1000);
//		setInterval(this.probe.bind(this), 500);
	},

	probe : function() {
		if(this.probing) {
			if(!this.isDone()) {
				this.update();
				setTimeout(this.probe.bind(this), 500);
			} else {
				this.probing = false;
				setTimeout(this.hide.bind(this), 1000);
			}
		} 
	},

	render : function() {
		this.container.innerHTML = '';

		this.extDiv = document.createElement('DIV');
		this.noteDiv = document.createElement('DIV');
		this.percentDiv = document.createElement('DIV');
		this.borderDiv = document.createElement('DIV');
		this.intDiv = document.createElement('DIV');

		this.container.appendChild(this.extDiv);
		this.extDiv.appendChild(this.noteDiv);
		this.extDiv.appendChild(this.borderDiv);
		this.extDiv.appendChild(this.percentDiv);
		this.borderDiv.appendChild(this.intDiv);

		this.ok = true;
		this.stop = false;

		this.extDiv.className = 'uploadTracerExtDiv';
		this.noteDiv.className = 'uploadTracerNoteDiv';
		this.percentDiv.className = 'uploadTracerPercentDiv';
		this.borderDiv.className = 'uploadTracerBorderDiv';
		this.intDiv.className = 'uploadTracerIntDiv';

		this.renderUpdate();
	},

	renderUpdate : function() {
		var done = this.getDonePortion();

		this.percentDiv.innerHTML = Math.round(done * 100) + '%';
		this.noteDiv.innerHTML = done > 0 ? done < 1 ? 'uploading...' : 'done!' : 'preparing...';
		this.intDiv.style.width = Math.round(done * 200) + 'px';
	},

	getDonePortion : function() {
		return this.state.bytesTotal > 0 ?
		           this.state.bytesRead / this.state.bytesTotal : 0;
	},

	isDone : function() {
		return this.getDonePortion() == 1;
	},

	update : function() {
		if(!this.pending) {

			var innerCallback = {
				success : function(o) {
					o.argument[0].pending = false;
					eval('o.argument[0].state = ' + o.responseText);
					o.argument[0].renderUpdate();
				},
				failure : function(o) {
					o.argument[0].pending = false;
				},
				timeout : 3000,
				argument : [this]
			};

			this.pending = true;

			var transaction = YAHOO.util.Connect.asyncRequest('GET', this.url, innerCallback, null);
		}
	},

	show : function() {
		this.container.style.visibility = 'visible';
	},
	
	hide : function() {
		this.container.style.visibility = 'hidden';
	}
});