/**

 * jquery.plupload.queue.js

 *

 * Copyright 2009, Moxiecode Systems AB

 * Released under GPL License.

 *

 * License: http://www.plupload.com/license

 * Contributing: http://www.plupload.com/contributing

 */



/* global jQuery:true, alert:true */



/**

jQuery based implementation of the Plupload API - multi-runtime file uploading API.



To use the widget you must include _jQuery_. It is not meant to be extended in any way and is provided to be

used as it is.



@example

	<!-- Instantiating: -->

	<div id="uploader">

		<p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>

	</div>



	<script>

		$('#uploader').pluploadQueue({

			url : '../upload.php',

			filters : [

				{title : "Image files", extensions : "jpg,gif,png"}

			],

			rename: true,

			flash_swf_url : '../../js/Moxie.swf',

			silverlight_xap_url : '../../js/Moxie.xap',

		});

	</script>



@example

	// Retrieving a reference to plupload.Uploader object

	var uploader = $('#uploader').pluploadQueue();



	uploader.bind('FilesAdded', function() {

		

		// Autostart

		setTimeout(uploader.start, 1); // "detach" from the main thread

	});



@class pluploadQueue

@constructor

@param {Object} settings For detailed information about each option check documentation.

	@param {String} settings.url URL of the server-side upload handler.

	@param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled.

	@param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message.

	@param {Array} [settings.filters=[]] Set of file type filters, each one defined by hash of title and extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR`

	@param {String} [settings.flash_swf_url] URL of the Flash swf.

	@param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs.

	@param {Number|String} [settings.max_file_size] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.

	@param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event.

	@param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message.

	@param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload.

	@param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog.

	@param {Boolean} [settings.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.

	@param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess.

	@param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}`

		@param {Number} [settings.resize.width] If image is bigger, it will be resized.

		@param {Number} [settings.resize.height] If image is bigger, it will be resized.

		@param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100).

		@param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally.

	@param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails.

	@param {String} [settings.silverlight_xap_url] URL of the Silverlight xap.

	@param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files.



	@param {Boolean} [settings.dragdrop=true] Enable ability to add file to the queue by drag'n'dropping them from the desktop.

	@param {Boolean} [settings.rename=false] Enable ability to rename files in the queue.

	@param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure.

*/

;(function($, o) {

	var uploaders = {};



	function _(str) {

		return plupload.translate(str) || str;

	}



	function renderUI(id, target) {

		// Remove all existing non plupload items

		target.contents().each(function(i, node) {

			node = $(node);



			if (!node.is('.plupload')) {

				node.remove();

			}

		});



		target.prepend(

			'<div class="plupload_wrapper plupload_scroll">' +

				'<div id="' + id + '_container" class="plupload_container">' +

					'<div class="plupload">' +

						'<div class="plupload_header">' +

							'<div class="plupload_header_content">' +

								'<div class="plupload_header_title">' + _('Select files') + '</div>' +

								'<div class="plupload_header_text">' + _('Add files to the upload queue and click the start button.') + '</div>' +

							'</div>' +

						'</div>' +



						'<div class="plupload_content">' +

							'<div class="plupload_filelist_header">' +

								'<div class="plupload_file_name">' + _('Filename') + '</div>' +

								'<div class="plupload_file_action">&nbsp;</div>' +

								'<div class="plupload_file_status"><span>' + _('Status') + '</span></div>' +

								'<div class="plupload_file_size">' + _('Size') + '</div>' +

								'<div class="plupload_clearer">&nbsp;</div>' +

							'</div>' +



							'<ul id="' + id + '_filelist" class="plupload_filelist"></ul>' +



							'<div class="plupload_filelist_footer">' +

								'<div class="plupload_file_name">' +

									'<div class="plupload_buttons">' +

										'<a href="#" class="plupload_button plupload_add" id="' + id + '_browse">' + _('Add Files') + '</a>' +

										'<a href="#" class="plupload_button plupload_start">' + _('Start Upload') + '</a>' +

									'</div>' +

									'<span class="plupload_upload_status"></span>' +

								'</div>' +

								'<div class="plupload_file_action"></div>' +

								'<div class="plupload_file_status"><span class="plupload_total_status">0%</span></div>' +

								'<div class="plupload_file_size"><span class="plupload_total_file_size">0 b</span></div>' +

								'<div class="plupload_progress">' +

									'<div class="plupload_progress_container">' +

										'<div class="plupload_progress_bar"></div>' +

									'</div>' +

								'</div>' +

								'<div class="plupload_clearer">&nbsp;</div>' +

							'</div>' +

						'</div>' +

					'</div>' +

				'</div>' +

				'<input type="hidden" id="' + id + '_count" name="' + id + '_count" value="0" />' +

			'</div>'

		);

	}



	$.fn.pluploadQueue = function(settings) {

		if (settings) {

			this.each(function() {

				var uploader, target, id, contents_bak;



				target = $(this);

				id = target.attr('id');



				if (!id) {

					id = plupload.guid();

					target.attr('id', id);

				}



				contents_bak = target.html();

				renderUI(id, target);



				settings = $.extend({

					dragdrop : true,

					browse_button : id + '_browse',

					container : id

				}, settings);



				// Enable drag/drop (see PostInit handler as well)

				if (settings.dragdrop) {

					settings.drop_element = id + '_filelist';

				}



				uploader = new plupload.Uploader(settings);



				uploaders[id] = uploader;



				function handleStatus(file) {

					var actionClass;



					if (file.status == plupload.DONE) {

						actionClass = 'plupload_done';

					}



					if (file.status == plupload.FAILED) {

						actionClass = 'plupload_failed';

					}



					if (file.status == plupload.QUEUED) {

						actionClass = 'plupload_delete';

					}



					if (file.status == plupload.UPLOADING) {

						actionClass = 'plupload_uploading';

					}



					var icon = $('#' + file.id).attr('class', actionClass).find('a').css('display', 'block');

					if (file.hint) {

						icon.attr('title', file.hint);	

					}

				}



				function updateTotalProgress() {

					$('span.plupload_total_status', target).html(uploader.total.percent + '%');

					$('div.plupload_progress_bar', target).css('width', uploader.total.percent + '%');

					$('span.plupload_upload_status', target).html(

						o.sprintf(_('Uploaded %d/%d files'), uploader.total.uploaded, uploader.files.length)

					);

				}



				function updateList() {

					var fileList = $('ul.plupload_filelist', target).html(''), inputCount = 0, inputHTML;



					$.each(uploader.files, function(i, file) {

						inputHTML = '';



						if (file.status == plupload.DONE) {

							if (file.target_name) {

								inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_tmpname" value="' + plupload.xmlEncode(file.target_name) + '" />';

							}



							inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_name" value="' + plupload.xmlEncode(file.name) + '" />';

							inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_status" value="' + (file.status == plupload.DONE ? 'done' : 'failed') + '" />';

	

							inputCount++;



							$('#' + id + '_count').val(inputCount);

						}



						fileList.append(

							'<li id="' + file.id + '">' +

								'<div class="plupload_file_name"><span>' + file.name + '</span></div>' +

								'<div class="plupload_file_action"><a href="#"></a></div>' +

								'<div class="plupload_file_status">' + file.percent + '%</div>' +

								'<div class="plupload_file_size">' + plupload.formatSize(file.size) + '</div>' +

								'<div class="plupload_clearer">&nbsp;</div>' +

								inputHTML +

							'</li>'

						);



						handleStatus(file);



						$('#' + file.id + '.plupload_delete a').click(function(e) {

							$('#' + file.id).remove();

							uploader.removeFile(file);



							e.preventDefault();

						});

					});



					$('span.plupload_total_file_size', target).html(plupload.formatSize(uploader.total.size));



					if (uploader.total.queued === 0) {

						$('span.plupload_add_text', target).html(_('Add Files'));

					} else {

						$('span.plupload_add_text', target).html(o.sprintf(_('%d files queued'), uploader.total.queued));

					}



					$('a.plupload_start', target).toggleClass('plupload_disabled', uploader.files.length == (uploader.total.uploaded + uploader.total.failed));



					// Scroll to end of file list

					fileList[0].scrollTop = fileList[0].scrollHeight;



					updateTotalProgress();



					// Re-add drag message if there is no files

					if (!uploader.files.length && uploader.features.dragdrop && uploader.settings.dragdrop) {

						$('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');

					}

				}



				function destroy() {

					delete uploaders[id];

					uploader.destroy();

					target.html(contents_bak);

					uploader = target = contents_bak = null;

				}



				uploader.bind("UploadFile", function(up, file) {

					$('#' + file.id).addClass('plupload_current_file');

				});



				uploader.bind('Init', function(up, res) {

					// Enable rename support

					if (!settings.unique_names && settings.rename) {

						target.on('click', '#' + id + '_filelist div.plupload_file_name span', function(e) {

							var targetSpan = $(e.target), file, parts, name, ext = "";



							// Get file name and split out name and extension

							file = up.getFile(targetSpan.parents('li')[0].id);

							name = file.name;

							parts = /^(.+)(\.[^.]+)$/.exec(name);

							if (parts) {

								name = parts[1];

								ext = parts[2];

							}



							// Display input element

							targetSpan.hide().after('<input type="text" />');

							targetSpan.next().val(name).focus().blur(function() {

								targetSpan.show().next().remove();

							}).keydown(function(e) {

								var targetInput = $(this);



								if (e.keyCode == 13) {

									e.preventDefault();



									// Rename file and glue extension back on

									file.name = targetInput.val() + ext;

									targetSpan.html(file.name);

									targetInput.blur();

								}

							});

						});

					}



					$('#' + id + '_container').attr('title', 'Using runtime: ' + res.runtime);



					$('a.plupload_start', target).click(function(e) {

						if (!$(this).hasClass('plupload_disabled')) {

							uploader.start();

						}



						e.preventDefault();

					});



					$('a.plupload_stop', target).click(function(e) {

						e.preventDefault();

						uploader.stop();

					});



					$('a.plupload_start', target).addClass('plupload_disabled');

				});



				uploader.bind("Error", function(up, err) {

					var file = err.file, message;



					if (file) {

						message = err.message;



						if (err.details) {

							message += " (" + err.details + ")";

						}



						if (err.code == plupload.FILE_SIZE_ERROR) {

							alert(_("Error: File too large:") + " " + file.name);

						}



						if (err.code == plupload.FILE_EXTENSION_ERROR) {

							alert(_("Error: Invalid file extension:") + " " + file.name);

						}

						

						file.hint = message;

						$('#' + file.id).attr('class', 'plupload_failed').find('a').css('display', 'block').attr('title', message);

					}



					if (err.code === plupload.INIT_ERROR) {

						setTimeout(function() {

							destroy();

						}, 1);

					}

				});



				uploader.bind("PostInit", function(up) {

					// features are populated only after input components are fully instantiated

					if (up.settings.dragdrop && up.features.dragdrop) {

						$('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');

					}

				});



				uploader.init();



				uploader.bind('StateChanged', function() {

					if (uploader.state === plupload.STARTED) {

						$('li.plupload_delete a,div.plupload_buttons', target).hide();

						uploader.disableBrowse(true);



						$('span.plupload_upload_status,div.plupload_progress,a.plupload_stop', target).css('display', 'block');

						$('span.plupload_upload_status', target).html('Uploaded ' + uploader.total.uploaded + '/' + uploader.files.length + ' files');



						if (settings.multiple_queues) {

							$('span.plupload_total_status,span.plupload_total_file_size', target).show();

						}

					} else {

						updateList();

						$('a.plupload_stop,div.plupload_progress', target).hide();

						$('a.plupload_delete', target).css('display', 'block');



						if (settings.multiple_queues && uploader.total.uploaded + uploader.total.failed == uploader.files.length) {

							$(".plupload_buttons,.plupload_upload_status", target).css("display", "inline");

							uploader.disableBrowse(false);



							$(".plupload_start", target).addClass("plupload_disabled");

							$('span.plupload_total_status,span.plupload_total_file_size', target).hide();

						}

					}

				});



				uploader.bind('FilesAdded', updateList);



				uploader.bind('FilesRemoved', function() {

					// since the whole file list is redrawn for every change in the queue

					// we need to scroll back to the file removal point to avoid annoying

					// scrolling to the bottom bug (see #926)

					var scrollTop = $('#' + id + '_filelist').scrollTop();

					updateList();

					$('#' + id + '_filelist').scrollTop(scrollTop);

				});



				uploader.bind('FileUploaded', function(up, file) {

					handleStatus(file);

				});



				uploader.bind("UploadProgress", function(up, file) {

					// Set file specific progress

					$('#' + file.id + ' div.plupload_file_status', target).html(file.percent + '%');



					handleStatus(file);

					updateTotalProgress();

				});



				// Call setup function

				if (settings.setup) {

					settings.setup(uploader);

				}

			});



			return this;

		} else {

			// Get uploader instance for specified element

			return uploaders[$(this[0]).attr('id')];

		}

	};

})(jQuery, mOxie);

