function ImageUploader(data) {
	this.Timer = null;
	this.allowedExts = '';
	this.ajaxPath = '';
	this.UUID = null;
	this.cancelPing = null;
	this.pingFrequency = 1000;
	this.StartTime = null;
	this.xMode = 'narrow';
	this.active = false;

	this.wrong_extension_warning_1 = this.wrong_extension_warning_2 = ''; 
	
	this.attachedFrame = '';
	this.OnStartUpload = null;
	this.OnSuccess = null;
	this.OnFailure = null;
	
	this.iframe = function() {
		var fName = this.attachedFrame;
		var frame = window.frames[fName];
		if(!frame) {
			var jFrame = $('iframe[name="' + fName + '"]');
			if(jFrame.length) {
				frame = jFrame[0].contentWindow;
			}
		}
		
		return frame;
	}
	
	this.form = function() {
		return $(this.iframe().document).find('form');
	};

	this.container = '';
	this.box = function() {
		return $(this.container);
	};

	this.OnStartUpload = function(uploader) {
		/*window.parent.*/startUploadBar(uploader);
	};
	this.OnInvalidUpload = function(uploader) {
		/*window.parent.*/voidUpload(uploader);
	};
	this.OnSuccess = function(uploader, imgID, imgFile, w, h) {
		/*window.parent.*/upload_complete(uploader, imgID, imgFile, w, h);
	};
	this.OnFailure = function(uploader, error) {
		/*window.parent.*/upload_error(uploader, error);
	};
	
	$.extend(this, data);
	
	this.Extend = function(data) {
		$.extend(this, data);
	};
	
	return this;
};

ImageUploader.Instances = ImageUploader.Instances || {};

ImageUploader.Attach = function(frame, data) {
	if(frame in ImageUploader.Instances) {
		ImageUploader.Instances[frame].Extend(data);
		return ImageUploader.Instances[frame];
	}
	var inst = new ImageUploader(data);
	inst.BindTo(frame);
	ImageUploader.Instances[frame] = inst;
	return inst;
};

ImageUploader.Find = function(frame) {
	return ImageUploader.Instances[frame];
};

ImageUploader.prototype.BindTo = function(frame) {
	this.attachedFrame = frame;
};

ImageUploader.FrameLoaded = function(event) {
	var self = this;
	var fName = self.name;
	var frame = window.frames[fName];
	if(!frame) {
		var jFrame = $('iframe[name="' + fName + '"]');
		if(jFrame.length) {
			frame = jFrame[0].contentWindow;
		}
	}
	
	if(!frame) {
		//something went wrong
		return false;
	}
	
	var data = frame.uploader_config || {};
	data.wrong_extension_warning_1 = wrong_extension_warning_1;
	data.wrong_extension_warning_2 = wrong_extension_warning_2;

	frame.UPL = ImageUploader.Attach(fName, data);
	return true;
};

ImageUploader.generateSID = function() {
	return Math.round(10000 * Math.random()) + '0'
			+ Math.round(10000 * Math.random());
};

ImageUploader.prototype.generateSID = function() {
	return ImageUploader.generateSID();
};

ImageUploader.prototype.StartUpload = function() {
	this.cancelPing = false;
	var form = this.form()[0];
	form.action = form.action.split('?')[0] + '?upload_id=' + this.UUID + '&frame_tag=' + this.attachedFrame;
	for ( var i = 0; i < form.elements.length; i++) {
		if (form.elements[i].type == 'file') {
			if (!this.checkExt(form.elements[i].value)) {
				this.RaiseInvalidUpload();
				return false;
			}
		}
	}
	this.active = true;
	
	this.RaiseStartUpload();
	form.submit();	
	return true;
};

ImageUploader.prototype.checkExt = function(value) {
	if (value == "") {
		return true;
	}
	var re = new RegExp("^.+\.(" + this.allowedExts + ")$", "i");
	if (re.test(value)) {
		return true;
	}
	alert(this.wrong_extension_warning_1 + ".\n"
			+ this.wrong_extension_warning_2 + ": "
			+ this.allowedExts.replace(/\|/g, ', ') + " \n\n");

	return false;
};

ImageUploader.prototype.pingUpload = function(firstTime) {
	var $this = this;
	// console.log('Starting pingUpload with', firstTime, 'and', cancelPing);
	if (typeof (firstTime) == 'undefined') {
		firstTime = false;
	}
	if (/^([0-9]{2,})$/.test(this.UUID) && !(firstTime && this.cancelPing)) {
		this.active = true;
		if (this.StartTime == null) {
			this.StartTime = new Date();
		}
		// console.log('requesting pingUpload');
		$.ajax({
			url: this.ajaxPath 
			, data: {
				id: this.UUID
				, rand1 : Math.random()
				, rand2 : Math.random()
			}
			, method: 'GET'
			, success: function(response) { $this.loadPing(response); }
			, error: function(error) { $this.ajaxFailure(error); }
			, dataType: 'json'
		});
		this.queuePing();
	} else {
		this.active = false;
		//return false; // alert('UUID is not set');
	}
};

ImageUploader.prototype.queuePing = function() {
	var $this = this;
	this.Timer = setTimeout(function() {
		$this.pingUpload();
	}, this.pingFrequency);
};

ImageUploader.prototype.stopProgressBar = function() {
	clearTimeout(this.Timer);
	this.Timer = null;
	this.cancelPing = true;
	this.UUID = null;
	this.active = false;

	var progBar = $('#progressBar1');
	var cntr = progBar.parent();
	
	var w = parseInt(cntr.css('width'));
	progBar.css({width : '1px' });

	var progLbl = $('#progressLabel1');
	progLbl.text('0% (Waiting)');
};

ImageUploader.prototype.ajaxFailure = function(error) {
	alert('Upload failed.');
	this.stopProgressBar();
	this.RaiseFailure(msg);
};

ImageUploader.prototype.uploadError = function(msg) {
	this.stopProgressBar();
	this.RaiseFailure('');
};

ImageUploader.prototype.uploadComplete = function(imgID, imgFile, w, h) {
	this.stopProgressBar();
	this.RaiseSuccess(imgID, imgFile, w, h);
};

ImageUploader.prototype.abortUpload = function() {
	this.stopProgressBar();
};

ImageUploader.prototype.loadPing = function(response) {
	if(!response) {
		return;
	}

	var now = new Date();
	var dt = (now.getTime() - this.StartTime.getTime()) / (this.pingFrequency);

	var stats = {
			done: response.Uploaded * 1.0
			, total: response.Total * 1.0
	};

	stats.speed = Math.round(stats.done / (1024 * dt));
	stats.remaining = Math.round((stats.total - stats.done) / (stats.speed * 1024));
	
	if(this.container.length && this.index) {
		this.loadPingInBox(stats);
	} else {
		this.loadPingStandalone(stats);
	}
};

ImageUploader.prototype.loadPingStandalone = function(stats) {
	if (stats.total > 0 && stats.done > 0) {
		var percent = stats.done / stats.total;

		var progBar = $('#progressBar1');
		var progWidth = progBar.width() * 1;
		
		var cntr = progBar.parent();
		
		var w = parseInt(cntr.css('width'));
		var pct = w * percent;
		if(pct > progWidth) {
			progBar.css({width : Math.round(pct) + 'px' });

			var progLbl = $('#progressLabel1');
			if (this.xMode == 'wide') {
				progLbl.text(Math.round(100 * percent) + '% (@' + stats.speed + 'KB/s, remaining ' + stats.remaining + ' s)');
			} else {
				progLbl.text(Math.round(100 * percent) + '% (' + stats.speed + 'KB/s)');
			}

		}
	}

	var progLbl = $('#progressLabel1');
	var str = progLbl.text();
	var parts = str.split('(');

	if (stats.done == 0) {
		progLbl.text(parts[0] + '(Waiting)');
	} else if(stats.done == stats.total) {
		progLbl.text(parts[0] + '(Processing)');
	}
};

ImageUploader.prototype.loadPingInBox = function(stats) {
	if(stats.total > 0 && stats.done > 0) {
		var percent = stats.done / stats.total;

		var pbox = this.box().find('.progressIn');
		var progWidth = pbox.width() * 1;

		var w = pbox.parent().width();

		var pct = w * percent;

		if(pct > progWidth) {
			pbox.css('width', Math.round(pct) + 'px');
	
			var pLbl = pbox.next();
			if(this.xMode == 'wide') {
				pLbl.text(Math.round(100 * percent) + '% (@' + stats.speed + 'KB/s, remaining ' + stats.remaining + ' s)');
			} else {
				pLbl.text(Math.round(100 * percent) + '% (' + stats.speed + 'KB/s)');
			}
		}
	}
	
	var lbox = this.box().find('.progressLabel');
	var str = lbox.text();
	var parts = str.split('(');
	if(stats.done == 0) {
		lbox.text(parts[0]+'(Waiting)');
	} else if(stats.done == stats.total) {
		lbox.text(parts[0] + '(Processing)');
	}
};

ImageUploader.prototype.RaiseStartUpload = function() {
	if(this.OnStartUpload) {
		this.OnStartUpload.call(null, this);
	}
};

ImageUploader.prototype.RaiseInvalidUpload = function() {
	if(this.OnInvalidUpload) {
		this.OnInvalidUpload.call(null, this);
	}
};

ImageUploader.prototype.RaiseFailure = function(msg) {
	if(this.OnFailure) {
		this.OnFailure.call(null, this, msg);
	}
};

ImageUploader.prototype.RaiseSuccess = function(imgID, imgFile, w, h) {
	if(this.OnSuccess) {
		this.OnSuccess.call(null, this, imgID, imgFile, w, h);
	}
};

