function uploadProgress( options )
{
	var self = this;
	var defaults = {
		redirect:'upload'
	};
	var settings = {};

	settings = $.extend({}, defaults, options);
	log(settings)

	// Assign values to private members.
	var	_storage				= '',
		_query					= '',
		_forceKB				= 0,
		_started				= false,
		_completed				= false,

		_iteration				= 0,
		_success_iteration		= 0,

		_progressMeter			= '',
		_transferRate			= '',
		_progressMeterBarDone	= '',
		_progressMeterText		= '',
		_progressPercent		= '',

		_requestInterval 		= 2.5,/* in seconds */

		_donet,
		_dones,
		_leftt,
		_lefts,
		_totalt,
		_totals,

		_xhr;


	// Private method.
	this.do_request = function(){

		_iteration++;

		//log('_iteration', _iteration);
		//log('_success_iteration', _success_iteration);


		if ( ! _completed )
		{
			if( _xhr && typeof(_xhr) == 'object' )
			{
				_xhr.abort();
			}

			//var path = settings.nginx_upload ? 'progress' : 'status';

			if( settings.nginx_upload )
			{
				var url = 'http://'+_storage+'/progress/?X-Progress-ID='+_query+'&callback=?';
			}
			else
			{
				var url = 'http://'+_storage+'/status/'+_query+'?callback=?';
			}



			_xhr = $.ajax({
				url:url,
				dataType:'json',
				data:{
					rand: Math.ceil(100000*Math.random()),
					is_ajax:true
				},
				jsonp:'callback',
				jsonpCallback:'upload_progress',
				success:function(data, textStatus, jqXHR){
					_success_iteration++;

					if( data.state == 'done' )
					{
						_xhr.abort();
						_completed = true;
					}

					self.update_table(data);
				},
//				error:function(XMLHttpRequest, textStatus, errorThrown){
//					log(' -- on error -- ');
//					log(XMLHttpRequest, ' XMLHttpRequest - ');
//					log(textStatus, ' textStatus - ');
//				},
				complete: function(XMLHttpRequest, textStatus){

					//log(' -- on complete -- ');
					//log( _iteration, '_iteration - ')
					//log( _success_iteration, '_success_iteration - ' )
					//log(XMLHttpRequest, ' XMLHttpRequest - ');
					//log(textStatus, ' textStatus - ');


					//if((_iteration-_success_iteration) < 50)
					//{
					//	setTimeout(function(){
					//		self.do_request();
					//	}, _requestInterval*1000);
					//}
				},
				type:'GET'
			});
		}

		if(( _iteration-_success_iteration ) < 50)
		{

		}

		if( ! _completed )
		{
			setTimeout(function(){
				self.do_request();
			}, _requestInterval*1000);
		}

		/*
		else
		{
			self.show_error();
		}
		*/
	};

/*
	this.show_error = function(){
		_progressMeter.hide();
		$('<div/>')
			.text('произошла ошибка ')
			.addClass('mes error')
			.insertAfter(_progressMeter);
	}
*/
	this.update_table = function(data){

		_progressMeter.show();

		_progressPercent = Math.ceil((data.progress/data.size)*100);

		if( _progressPercent >= 100 )
		{
			_completed = true;
		}

		_progressMeterBarDone.css({
			width:_progressPercent+'%'
		});
		_progressMeterText.text('Закачано: '+_progressPercent+'%');


		var totaltime 						= parseInt((data.elapsedtime*100)/_progressPercent);
		var totaltime_forprint 				= self.format_timespan_with_unit(totaltime,"&nbsp;");
		var remainingtime_forprint			= self.format_timespan_with_unit((totaltime-data.elapsedtime),"&nbsp;");
		var elapsedtime_forprint			= self.format_timespan_with_unit(data.elapsedtime,"&nbsp;");
		var force_MB						= data.size > 999999 ? 1 : 0;
		var total_upload_size_forprint		= self.format_filesize_with_unit(data.size,"&nbsp;",force_MB);
		var remaining_upload_size_forprint	= self.format_filesize_with_unit((data.size-data.progress),"&nbsp;",force_MB);
		var completed_upload_size_forprint	= self.format_filesize_with_unit(data.progress,"&nbsp;",force_MB);
		var transfer_rate					= self.format_filesize_with_unit((data.progress/data.elapsedtime),"&nbsp;",force_MB);

		if(_donet.size())
		{
			_donet.html(elapsedtime_forprint);
		}

		if(_dones.size())
		{
			_dones.html(completed_upload_size_forprint);
		}

		if(_leftt.size())
		{
			_leftt.html(remainingtime_forprint);
		}

		if( _lefts.size() )
		{
			_lefts.html(remaining_upload_size_forprint);
		}

		if(_totalt.size())
		{
			_totalt.html(totaltime_forprint);
		}

		if(_totals.size())
		{
			_totals.html(total_upload_size_forprint);
		}

		if( _transferRate.size() )
		{
			_transferRate.html("Скорость закачки: "+transfer_rate+"/s");
		}
	};

	this.format_filesize_with_unit = function(num,space,forceMB){
		var unit;
		if(((num>999999)||forceMB)&&!_forceKB)
		{
			num=num/(1024*1024);
			num=num.toString();
			var testnum=num.replace(/^(\d+\.\d).*/,"$1");
			if(testnum=="0.0")
			{
				testnum=num.replace(/^(\d+\.\d\d).*/,"$1")
			}
			if(testnum=="0.00")
			{
				testnum=num.replace(/^(\d+\.\d\d\d).*/,"$1")
			}
			num=testnum;
			unit="MB"
		}
		else
		{
			num=parseInt(num/(1024));
			unit="KB"
		}
		return num+space+unit
	};

	this.format_timespan_with_unit = function(num,space){

		var unit;
		if(num>=(60*60))
		{
			var secs_left=num%(60*60);
			var mins_left=secs_left/60;
			mins_left=mins_left.toString();
			mins_left=mins_left.replace(/^(\d+)\..*/,"$1");
			mins_left=mins_left.replace(/^(\d)$/,"0$1");
			num=num/(60*60);
			num=num.toString();
			num=num.replace(/^(\d+)\..*/,"$1");
			num=num+space+"h"+space+mins_left+space+"m";
			space="";
			unit="";
		}
		else
		{
			if(num>=60)
			{
				var secs_left = num%60;
				secs_left = secs_left.toString().replace(/^(\d)$/,"0$1");
				num = num/60;
				num = num.toString();
				num = num.replace(/^(\d+)\..*/,"$1");
				num = num.replace(/^(\d)$/,"0$1");
				num = num+space+"m"+space+secs_left+space+"s";
				space = "";
				unit = "";
			}
			else
			{
				unit = "s";
			}
		}
		return num+space+unit
	}

	// Public methods.
	return{
		start: function(options){

			if( ! $('#show_progress_bar').is(':checked') )
			{
				_storage 				= $('#upload_host').val();
				_query					= $('#progress_bar').val();

				_progressMeter			= $('#progressMeter');
				_transferRate			= $('#transferRate');
				_progressMeterBarDone	= $('#progressMeterBarDone');
				_progressMeterText		= $('#progressMeterText');

				_donet					= $('#donet');
				_dones					= $('#dones');
				_leftt					= $('#leftt');
				_lefts					= $('#lefts');
				_totalt					= $('#totalt');
				_totals					= $('#totals');
				_completed				= false;

				self.do_request();
			}
		},
		stop: function(){
			_completed = true;
			_xhr.abort();
		}
	}
}

