/*
requires jquery
*/

var AWCAsyncUpload = jQuery.extend({},{
	
	_poll_frequnecy: 1000,
	_update_retry_frequnecy: 500,
	_progress_update_frequnecy: 250,
	_update_ajax_url: '/_awc_ajax',
	_form_post_url: '/_awc_handle_async_file_upload',
	
	_update_request_pending: {},
	_in_upload: {},
	_upload_start_ms: {},
	_upload_est_ms: {},
	_upload_complete: {},
	_progress_display_stack: {},

	_upload_id_base: false,
	_upload_id_offset: 0,

	_poll_counter: 0,
	
	_submitting: {},
	
	doUpload: function(id) {
		// make sure the file is not blank
		var file_value = jQuery('#'+id+'_file_input').val();
		if (!file_value.length) return false;
		
		// check to see if we are uploading already
		if (typeof(this._in_upload[id]) != 'undefined' && this._in_upload[id]) return false;
		

		var all_upload_ids = this._getAllUploadIDs(id);
		
		// find ids that are actually uploading
		var disabled_ids = [];
		for (var i=0; i < all_upload_ids.length; i++) {
			var upload_id = all_upload_ids[i];
			file_value = jQuery('#'+upload_id+'_file_input').val();
			if (file_value.length) {
				// if this is an active file, but not our id, deactivate it
				if (upload_id != id) {
					disabled_ids[disabled_ids.length] = upload_id;
					this._disableFileInput(upload_id);
					// this._debugLog('disableFileInput '+upload_id+'')
				}
			}
		}
		
		var form_el = this._getForm(id);
		var old_action = ''+form_el.action;
		var old_target = ''+form_el.target;
		
		form_el.target = (id.replace('\\|','|'))+'_awc_target_upload';
		form_el.action = this._form_post_url;

		// init the uplod beginning
		this._initUploadData(id);
		this._initUploadDisplay(id);
		
		// increment and set the UPLOAD_IDENTIFIER
		this._incrementUID();
		var uid = this._getUID();
		form_el.UPLOAD_IDENTIFIER.value = uid;
		form_el.upload_active_field_id.value = id;

		// submit the form
		form_el.submit();
		this._upload_start_ms[id] = (new Date()).getTime();
		

		// restore the form
		setTimeout(function() {
			form_el.target = old_target;
			form_el.action = old_action;
			form_el.UPLOAD_IDENTIFIER.value = '';
			form_el.upload_active_field_id.value = '';
		}, 1);

		// begin checking for progress
		this._setUpdateTimeout(id, uid);
		
		// re-enable disabled file inputs
		for (var i=0; i < disabled_ids.length; i++) {
			var disabled_id = disabled_ids[i];
			this._enableFileInput(disabled_id);
			// this._debugLog('enableFileInput '+disabled_id+'')
		};
		
		// disable this file input
		this._disableFileInput(id);
		
		return true;
	},
	
	uploadRemainingFilesAndSubmit: function(form) {
		var all_upload_ids = this._getAllUploadIDsByForm(form);
		if (all_upload_ids.length) {
			var form_name = this._getFormName(all_upload_ids[0]);
		}
		
		// find ids that are actually uploading
		for (var i=0; i < all_upload_ids.length; i++) {
			var upload_id = all_upload_ids[i];
			
			file_value = jQuery('#'+upload_id+'_file_input').val();
			if (file_value.length) {
				// has a file value
				if (typeof(this._upload_complete[upload_id]) == 'undefined' || !this._upload_complete[upload_id]) {
					// this._debugLog('file '+upload_id+' has a value, but is not uploaded yet.');
					// has data, but has not been uploaded
					this._submitting[form_name] = true;

					// do the upload
					this.doUpload(upload_id);
					
					// cancel the submit
					return false;
				}
				
				// is currently submitting
				if (typeof(this._in_upload[upload_id]) != 'undefined' && this._in_upload[upload_id] == true) {
					// this._debugLog('file '+upload_id+' is currently uploading.');

					// put the form in submitting mode
					this._submitting[form_name] = true;

					// cancel the submit
					return false;
				}
			}
		}
		
		// submit the form
		setTimeout(function() {
			form.submit();
		}, 100)
		
		// cancel the natural submit
		return false;
	},
	
	fileReceived: function(id, tmp_id, file_name) {
		jQuery('#'+id+'_tmp_id').val(tmp_id);
		this._finalizeUploadData(id);
		// this._debugLog('_finalizeUploadData('+id+')');
		this._setUploadPercentage(id, 1);
		
		// remove File Input
		this._disableFileInput(id);
		jQuery('#'+id+'_upload').hide();

		// remove progress
		jQuery('#'+id+'_progress').hide();

		// show received text
		jQuery('#'+id+'_received_filename').empty().append(file_name);
		jQuery('#'+id+'_received').show();
		
		// if we are submitting, try submitting the form
		var form_name = this._getFormName(id);
		if (typeof(this._submitting[form_name]) != 'undefined' && this._submitting[form_name]) {
			return this.uploadRemainingFilesAndSubmit(this._getForm(id));
		}
	},
	
	fileFailed: function(id, tmp_id, file_name, err_string) {
		jQuery('#'+id+'_tmp_id').val(tmp_id);
		this._finalizeUploadData(id);
		// this._debugLog('_finalizeUploadData('+id+')');
		this._setUploadPercentage(id, 1);
		
		// remove File Input
		this._disableFileInput(id);
		jQuery('#'+id+'_upload').hide();

		// remove progress
		jQuery('#'+id+'_progress').hide();

		// show received text
		jQuery('#'+id+'_received_filename').empty().append('none');
		jQuery('#'+id+'_received').show();
		
		/* keep */ alert('Failed to upload "'+file_name+'". '+err_string+'');
	},

	clearFile: function(id) {
		jQuery('#'+id+'_tmp_id').val('');
		this._setUploadPercentage(id, 0);
		
		this._enableFileInput(id);
		jQuery('#'+id+'_upload').show();

		jQuery('#'+id+'_received').hide();
		jQuery('#'+id+'_received_filename').empty();

		jQuery('#'+id+'_file_input').val('');

		// mark upload not complete, so submit will cause it to upload again
		this._upload_complete[id] = false;
	},
	
	resetUploadInput: function(id) {
		this._enableFileInput(id);
		jQuery('#'+id+'_tmp_id').val('');
	},
	
	addFile: function(base_id) {
		var el = this._getNextHiddenFileUpload(base_id);
		if (el) el.show();
		
		this._checkAddFileLink(base_id);
	},
		
	_getNextHiddenFileUpload: function(base_id) {
		// get the next available div
		var i=0;
		var done=false;
		while(!done) {
			++i;
			var el = jQuery('#'+base_id+'_'+i+'_file_upload_container');
			// alert('_getNextHiddenFileUpload jQuery(\'#'+base_id+'_'+i+'_file_upload_container\') = '+el+' el.length='+el.length)
			if (el.length) {
				// object exists
				if (el.is(':hidden')) {
					return el;
				}
			} else {
				// element doesn't exist
				return false;
			}

			// safety
			if (i > 999) break;
		}
		return false;
	},
	
	_checkAddFileLink: function(base_id) {
		var el = this._getNextHiddenFileUpload(base_id);
		if (!el) {
			// hide the add file link
			jQuery('#'+base_id+'_add_file').hide();
		}
	},

	_sendUpdateProgress: function(id, uid) {
		if (this._in_upload[id]) {
			// jQuery('#log').append('<p>_sendUpdateProgress('+id+', '+uid+')</p>');
			
			if (typeof(this._update_request_pending[id]) != 'undefined' && this._update_request_pending[id]) {
				// a request is pending - don't send another
				this._setUpdateTimeoutForPendingRequest(id, uid);
			} else {
				this._update_request_pending[id] = true;
				var get_data = {'uid': uid, 'req': (++this._poll_counter).toString(16), 'method':'AsyncFileUploadUtil::updateStatus'};
				jQuery.getJSON(this._update_ajax_url, get_data, function(response_data) { AWCAsyncUpload._receiveUpdateProgress(id, response_data) });
				this._setUpdateTimeout(id, uid);
			}
		}
	},
	
	_receiveUpdateProgress: function(id, response_data) {
		// jQuery('#log').append('<p>_receiveUpdateProgress id='+id+', response_data='+response_data+'</p>');
		if (this._in_upload[id]) {
			if (response_data) {
				this._upload_est_ms[id] = (parseInt(response_data.est_sec) + parseInt(response_data.time_last) - parseInt(response_data.time_start)) * 1000;
				// this._debugLog('_upload_est_ms='+this._upload_est_ms[id])

				if (typeof(this._progress_display_stack[id]) == 'undefined') this._progress_display_stack[id] = 0;
				++this._progress_display_stack[id];

				this._updateProgressDisplay(id);
			}
		}
		this._update_request_pending[id] = false;
	},
	
	_updateProgressDisplay: function(id) {
		if (this._in_upload[id]) {
			var elapsed_ms = (new Date()).getTime() - this._upload_start_ms[id];
			var percentage = (this._upload_est_ms[id] > 0 ? (elapsed_ms / this._upload_est_ms[id]) : 0);
			// this._debugLog('elapsed_ms='+elapsed_ms+' percentage='+percentage+'')
			percentage = Math.min(percentage, 1);

			this._setUploadPercentage(id, percentage);

			// stack control 
			// if (typeof(this._progress_display_stack[id]) == 'undefined') this._progress_display_stack[id] = 0;
			// if (this._progress_display_stack[id] > 0) --this._progress_display_stack[id];
			// 
			// if (this._progress_display_stack[id] == 0) {
			// 	++this._progress_display_stack[id];
			// 	window.setTimeout("AWCAsyncUpload._updateProgressDisplay('"+id+"')", this._progress_update_frequnecy);
			// }
		}
	},

	_setUploadPercentage: function(id, percentage) {
		var int_percent = Math.round(percentage * 100);
		var new_text = int_percent+'%';
		jQuery('#'+id+'_progress_text').empty().append(new_text);
		jQuery('#'+id+'_bar').width(int_percent+'%');
	},


	_initUploadData: function(id) {
		this._in_upload[id] = true;
		this._progress_display_stack[id] = 0;
	},
	_finalizeUploadData: function(id) {
		this._in_upload[id] = false;

		// mark as received
		this._upload_complete[id] = true;
	},


	_initUploadDisplay: function(id) {
		jQuery('#'+id+'_progress').show();
	},

	
	_getForm: function(id) {
		if (!jQuery('#'+id+'_file_input').length) {
			alert('failed to find form for id '+id);
			return false;
		}

		return jQuery('#'+id+'_file_input').get(0).form;
		// return document.getElementById(id+'_file_input').form;
	},
	_getFormName: function(id) {
		return this._getForm(id).name;
	},
	
	_getAllUploadIDs: function(id) {
		var form_el = this._getForm(id);
		return this._getAllUploadIDsByForm(form_el);
	},

	_getAllUploadIDsByForm: function(form_el) {
		var upload_ids = [];
		for (var i=0; i < form_el.elements.length; i++) {
			var element = form_el.elements[i];
//			alert('for '+element.id+' element.id.substr(element.id.length-11, element.id.length)='+element.id.substr(element.id.length-11, element.id.length)+'')
			if (element.id.substr(element.id.length-11, element.id.length) == '_file_input') {
				upload_ids[upload_ids.length] = (element.id.substr(0, element.id.length-11)).replace('|','\\|');
			}
		};
		return upload_ids;
	},
	
	_setUpdateTimeout: function(id, uid) {
		window.setTimeout("AWCAsyncUpload._sendUpdateProgress('"+id+"','"+uid+"')", this._poll_frequnecy);
	},
	
	_setUpdateTimeoutForPendingRequest: function(id, uid) {
		window.setTimeout("AWCAsyncUpload._sendUpdateProgress('"+id+"','"+uid+"')", this._update_retry_frequnecy);
	},
	
	_disableFileInput: function(id) {
		// this breaks chrome
		// jQuery('#'+id+'_file_input').attr('disabled','disabled');
		jQuery('#'+id+'_upload_button').attr('disabled','disabled');
	},
	_enableFileInput: function(id) {
		// jQuery('#'+id+'_file_input').removeAttr('disabled');
		jQuery('#'+id+'_upload_button').removeAttr('disabled');
	},
	
	
	_getUID: function() {
		if (this._upload_id_base == false) {
			var ms_per_second = 100; // constant
			var ms_per_minute = 6000; // ms_per second * 60;
			var ms_per_hour   = 360000; // ms_per_minute * 60;
			var d = new Date();
			var ms = Math.abs((d.getUTCHours() * ms_per_hour) + (d.getUTCMinutes() * ms_per_minute) + (d.getUTCSeconds() * ms_per_second) + d.getUTCMilliseconds());
			this._upload_id_base = ms.toString(16)+'-'+Math.round(Math.random() * 65536).toString(16);
		}
		return this._upload_id_base + '-' + this._upload_id_offset.toString(16);
	},
	
	_incrementUID: function() {
		++this._upload_id_offset;
	},
	
	_debugLog: function(text) {
		jQuery('body').append(text+'<br/>');
	},

	_end: {}
});

