/**
 * Create an uploader.
 *
 * The `.presentationUiUploader()` method make an element editable on click the element.
 *
 * Only applicable to <input type="file"> nodes.
 *
 * ### Examples
 * Loads the Uploader to an input field to upload images.l,
 *
 * JavaScript:
 *
 *
 *     <input type="file" name="NewFile" class="ep-js" data-js="de_epages.presentationUiUploader({
 *       multiple:false,
 *       accept:'image/*',
 *       big:true,
 *       data:{
 *         ChangeAction:'SaveImage',
 *         ObjectID:#ObjectID,
 *         SCALE_WIDTH_l:#Shop.ProductImageLargeWidth,
 *         SCALE_HEIGHT_l:#Shop.ProductImageLargeHeight,
 *         SCALE_WIDTH_m:200,
 *         SCALE_WIDTH_s:100,
 *         SCALE_HEIGHT_s:100,
 *         SCALE_WIDTH_h:150,
 *         SCALE_HEIGHT_h:150,
 *         SCALE_WIDTH_xs:50,
 *         SCALE_HEIGHT_xs:33,
 *         SCALE_NAME_m:'ImageMedium',
 *         SCALE_NAME_s:'ImageSmall',
 *         SCALE_NAME_h:'ImageHotDeal'
 *       },
 *       callback:'?ViewAction='+ep.config.viewAction+'&ObjectID='+ep.config.objectId+'&DialogArea=ViewArea'
 *     })"/>
 *
 *
 * @class jQuery.ui.presentationUiUploader
 * @extends jQuery.widget
 *
 * @uses jQuery.dict
 * @uses jQuery.tmpl
 * @uses jQuery.i18n
 * @uses jQuery.expr
 * @uses jQuery.fn.form
 * @uses jQuery.ui.widget
 * @uses jQuery.ui.progressbar
 * @uses de_epages
 * @uses ep.ajaxTransport
 * @uses ep.ui.dialog
 * @since 6.12.0
 */

/**
 * @cfg {String} [accept] A string of MIME types and/or MIME type groups.
 */

/**
 * @cfg {String} [url] A string containing the URL to which the request is sent.
 */

/**
 * @cfg {String} [buttonText] A string for the upload button
 */

/**
 * @cfg {Object} [data] A map of additional data to send with the request.
 */

/**
 * @cfg {Function,String} [callback] A url to open or method to call when upload process is finished. The callback method receives data and statusText as arguments.
 */

/**
 * @cfg {Boolean} [multiple] A boolean indication whether to allow muplitple files to upload.
 */

/**
 * @cfg {Boolean} [big] A boolean boolean short handle set style big.
 */

/**
 * @cfg {String} [style] One of the available styles: normal,big,icon.
 */

/**
 * @cfg {Array} [exists] An array including already existing files.
 */

/**
 * See `jQuery.ui.presentationUiUploader` for details.
 *
 * @param {Object} [options] A map of additional options pass to the method.
 * @param {String} [accept] A string of MIME types and/or MIME type groups.
 * @param {String} [url] A string containing the URL to which the request is sent.
 * @param {String} [buttonText] A string for the upload button
 * @param {Object} [data] A map of additional data to send with the request.
 * @param {Function,String} [callback] A url to open or method to call when upload process is finished. The callback method receives data and statusText as arguments.
 * @param {Boolean} [multiple] A boolean indication whether to allow muplitple files to upload.
 * @param {Boolean} [big] A boolean boolean short handle set style big.
 * @param {String} [style] One of the available styles: normal,big,icon.
 * @param {Array} [exists] An array including already existing files.
 *
 * @method presentationUiUploader
 * @member jQuery
 *
 * @since 6.12.0
 */

/*
 * @copyright		© Copyright 2006-2010, epages GmbH, All Rights Reserved.
 *
 * @module			de_epages.presentation.ui.uploader
 *
 * @revision		$Revision: 1.18 $
 */

define("de_epages/presentation/ui/uploader", [
	"jquery",
	"ep",
	"de_epages",
	"util/mime",
	"util/string",
	"$dict!../dictionary",
	"$tmpl!./uploader-progress",
	"$tmpl!./uploader-error",
	"$tmpl!./uploader-replace",

	"jquery/i18n",
	"jquery/expr",
	"jquery/cookie",
	"jquery/fn/form",
	"jquery/ui/widget",
	"jquery/ui/progressbar",
	"ep/ajax",
	"ep/ui/input",
	"ep/ui/form",
	"ep/ui/dialog",
	"de_epages/presentation/ajaxtransport"
], function ($, ep, de_epages, mime, str, presentationDict, tmplUploaderProgress, tmplUploaderError, tmplUploaderReplace) {

	/*
	 * @dictionary		ep.dict
	 *
	 * @translation		{Cancel}
	 *					{Ignore}
	 *					{Replace}
	 *
	 * @dictionary		de_epages.presentation.dictionary
	 *
	 * @translation		{FileUploadSingle}
	 *					{FileUploadMultiple}
	 *					{UploaderError}
	 *					{UploaderReplace}
	 *					{FixErrors}
	 *					{FilesUploaded}
	 *					{FileSizeLimitError}
	 *					{InternalServerError}
	 *					{FontLicenseRestricted}
	 *					{MimetypeNotAcceptError}
	 *					{UnknownError}
	 *					{FeatureLimitExceeded}
	 *					{InvalidMP3File}
	 *					{InvalidImageFile}
	 *					{ImageExceedsMegapixels}
	 *					{VirusFoundError}
	 *					{FileAlreadyExistsOnServer}
	 *					{InvalidImageSize}
	 */

	var undef,

		tCancel = presentationDict.translate('Cancel'),
		tIgnore = presentationDict.translate('Ignore'),
		tReplace = presentationDict.translate('ReplaceFiles'),
		tUploadFile = presentationDict.translate('FileUploadSingle'),
		tUploadFiles = presentationDict.translate('FileUploadMultiple'),
		tUploaderError = presentationDict.translate('UploaderError'),
		tUploaderReplace = presentationDict.translate('FileUploadMultiple'),
		tFixErrors = presentationDict.translate('FixErrors'),
		tFilesUploaded = presentationDict.translate('FilesUploaded'),
		tAlreadyExists = presentationDict.translate('FileAlreadyExistsOnServer'),

		tmplHelper = function () {
			return {
				i: 0,
				even: function () {
					return (this.i++) % 2 === 0;
				},
				shrink: function (string) {
					return str.shrink(string, {
						ratio: 0.5,
						length: 40
					});
				},
				translate: function (string) {
					var before = string.replace(/ /g, ''),
						after = presentationDict.translate(before);

					return after !== before ? after : presentationDict.translate('UnknownError');
				}
			};
		};

	$.widget("ui.presentationUiUploader", {
		options: {
			//	multiple:	false,
			//	accept:		'*/*',
			exists: [],
			style: 'normal',
			big: false,
			callback: $.noop,
			url: '?',
			tokenName: 'SecToken',
			data: {
				'ViewAction': 'JSONViewResponse'
			}
		},

		_create: function () {
			var self = this,
				o = self.options;

			self.elem = self.element
				.attr("size", "1")
				.addClass('de_epages-presentationUiUploader-button');

			// create custom ui
			self.custom = $('<span/>')
				.addClass('ep-uiInput-custom ep-uiInput ep-uiInput-button')
				.insertAfter(self.elem);

			// bind upload handle
			self.elem
				.on('change.presentationUiUploader', $.proxy(self, '_upload'));

			// stack of item data
			self.dataStack = [];

			// init options
			self._setOptions({
				'accept': mime.mime(o.accept || self.elem.attr('accept') || '*/*'),
				'multiple': o.multiple || self.elem.attr('multiple') || false,
				'style': o.big ? 'big' : o.style,
				'disabled': !!o.disabled
			});
		},

		_setOption: function (name, value) {
			var o = this.options;

			if (value !== undef) {
				switch (name) {
				case 'accept':
					this.elem.attr(name, mime.mime(value));
					break;
				case 'multiple':
					this.elem.attr(name, value);
					this._setOption('style', o.style);
					break;
				case 'big':
					this._setOption('style', 'big');
					break;
				case 'style':
					switch (value) {
					case 'big':
						this.custom
							.html('<span class="ep-sprite ep-sprite-s ico_s_fileupload"></span>' + (o.buttonText || (o.multiple ? tUploadFiles : tUploadFile)))
							.addClass('ep-uiInput-big');
						break;
					case 'icon':
						this.custom
							.html('<span class="ep-sprite ep-sprite-s ico_s_fileupload ep-uiInput-buttonSpriteOnly"></span>')
							.removeClass('ep-uiInput-big');
						break;
					case 'big-icon':
						this.custom
							.html('<span class="ep-sprite ep-sprite-m ico_m_fileupload ep-uiInput-buttonSpriteOnly"></span>')
							.addClass('ep-uiInput-big');
						break;
					default:
						this.custom
							.html('<span class="ep-sprite ep-sprite-s ico_s_fileupload"></span>' + (o.buttonText || (o.multiple ? tUploadFiles : tUploadFile)))
							.removeClass('ep-uiInput-big');
						break;
					}
					break;
				}
			}
			return this._superApply(arguments);
		},

		// handle addClass to the wrap
		addClass: function (name) {
			this.elem.addClass(name);
		},

		// handle removeClass to the wrap
		removeClass: function (name) {
			this.elem.removeClass(name);
		},

		_upload: function (event, doReplace) {
			var self = this,
				o = self.options,
				files = self.elem[0].files,
				filesCheck = [],
				filesExists = [],
				cookies = $.cookie();

			self.statusText = '';

			self._errorClose({
				close: $.noop
			});

			for (var i = 0, iLength = self.dataStack.length; i < iLength; i++) {
				if (self.dataStack[i].ERROR) {
					self.dataStack.splice(i, 1);
					iLength--;
					i--;
				}
			}

			// ask for replace exixting files
			if (!doReplace && o.exists.length) {
				if (!files) {
					files = [{
						name: self.elem.val()
					}];
				}

				filesCheck = $.map(files, function (file, i) {
					return file.name || file.fileName;
				});

				ep.ajax({
					async: false,
					dataType: 'json',
					data: {
						ViewAction: "JSONUnicodeConverter",
						ObjectID: ep.config.siteId,
						Type: "File",
						Strings: filesCheck
					}
				})
					.done(function (data) {
						filesCheck = data.Strings;
					});

				filesExists = $.map(filesCheck, function (name, i) {
					return $.inArray(name, o.exists) >= 0 ? name : null;
				});

				if (filesExists.length) {
					self._uploadReplace(filesExists);
					return;
				}
			}

			self._progressOpen({
				close: function (event) {
					self._uploadCancel();
				}
			});

			// provide a flag for the server
			o.data.ReplaceExistingFiles = doReplace ? 1 : 0;

			// check if security token exists and add hidden input with security cookie information
			if (cookies[o.tokenName]) {
				o.data[o.tokenName] = cookies[o.tokenName];
			}

			self.uploadXHR = $.ajax({
				url: o.url,
				data: o.data,
				dataType: 'json',
				file: self.elem[0],
				fileMimeAccept: o.accept
			})
				.progress($.proxy(self, '_uploadProgress'))
				.done($.proxy(self, '_uploadSuccess'))
				.fail($.proxy(self, '_uploadError'));
		},

		_uploadReplace: function (filesReplace) {
			this._replaceCreate();
			this.replace
				.element
				.html(tmplUploaderReplace([{
					items: filesReplace,
					tAlreadyExists: tAlreadyExists
				}], tmplHelper()));
			this._replaceOpen();
		},

		_uploadCancel: function () {
			this.uploadXHR.abort();
			this._errorClose();
		},

		_uploadProgress: function (event, statusText, jqXHR) {
			var valueItem = event.loaded * 100 / event.total,
				valueAll = event.itemLoaded * 100 / event.itemTotal;

			this.progressbarItem.progressbar('value', valueItem);
			this.progresstextItem.text(str.shrink(event.data.item.fileName, {
				ratio: 0.5,
				length: 65
			}));
			this.progressbarAll.progressbar('value', valueAll);
			this.progresstextAll.text(tFilesUploaded + ': ' + event.itemLoaded + ' / ' + event.itemTotal);

			if (/(success|error)/.test(statusText)) {
				this.dataStack.push(event.data);
			}
		},

		_uploadSuccess: function (data, statusText, jqXHR) {
			this.statusText = statusText;
			this._progressClose({
				close: $.noop
			});
			this._uploadComplete();
		},

		//#JSCOVERAGE_IF 0
		_uploadError: function (jqXHR, statusText, errorThrown) {
			var self = this;
			self.statusText = statusText;
			self._errorCreate();
			self.error
				.element
				.html(tmplUploaderError([{
					items: self.dataStack
				}], tmplHelper()));
			self._progressClose({
				close: $.noop
			});
			self._errorOpen({
				close: function () {
					self._uploadComplete();
				}
			});
		},
		//#JSCOVERAGE_ENDIF

		_uploadComplete: function () {
			var o = this.options,
				dataStack = this.dataStack,
				statusText = this.statusText,
				formNode = $(this.elem[0].form);

			this.elem.formReset();
			this.dataStack = [];
			this.statusText = '';

			if ($.type(o.callback) == 'string') {
				if (formNode.length) {
					formNode.uiForm('option', 'showSaveWarn', false);
				}
				location.href = o.callback;
			} else {
				o.callback(dataStack, statusText);
				if (formNode.length) {
					formNode.trigger('change');
				}
			}
		},

		_progressOpen: function (options) {
			if (!this.progress) {
				this._progressCreate();
			}
			if (options) {
				this.progress.option(options);
			}
			this.progress.open();
		},

		_progressClose: function (options) {
			if (this.progress) {
				if (options) {
					this.progress.option(options);
				}
				this.progress.close();
			}
		},

		_progressCreate: function () {
			if (!this.progress) {
				var self = this;

				this.progress = $('<div class="de_epages-presentationUiUploader">')
					.html(tmplUploaderProgress({}))
					.uiDialog({
						width: 350,
						modal: true,
						autoOpen: false,
						title: self.options.multiple ? tUploadFiles : tUploadFile,
						buttons: {
							cancel: {
								text: tCancel,
								click: function () {
									self._progressClose();
								}
							}
						}
					})
					.find('.de_epages-presentationUiUploader-progressBar')
					.progressbar()
					.each(function (i) {
						var elem = $(this);
						self[i ? 'progressbarAll' : 'progressbarItem'] = elem;
						self[i ? 'progresstextAll' : 'progresstextItem'] = elem.next();
					})
					.end()
					.uiDialog('Instance');
			}
		},

		_errorOpen: function (options) {
			if (!this.error) {
				this._errorCreate();
			}
			if (options) {
				this.error.option(options);
			}
			this.error.open();
		},

		_errorClose: function (options) {
			if (this.error) {
				if (options) {
					this.error.option(options);
				}
				this.error.close();
			}
		},

		_errorCreate: function () {
			if (!this.error) {
				var self = this;

				this.error = $('<div class="de_epages-presentationUiUploader">')
					.html(tmplUploaderError({}))
					.uiDialog({
						width: 350,
						modal: true,
						autoOpen: false,
						title: tUploaderError,
						buttons: {
							fixit: {
								text: tFixErrors,
								'class': 'epWidth-160',
								click: function () {
									self._errorClose({
										close: $.noop
									});
									self.custom.trigger('click');
								}
							},
							ignore: {
								text: tCancel,
								click: function () {
									self._errorClose();
								}
							}
						}
					})
					.uiDialog('Instance');
			}
		},

		_replaceOpen: function (options) {
			if (!this.replace) {
				this._replaceCreate();
			}
			if (options) {
				this.replace.option(options);
			}

			this.replace.open();
		},

		_replaceClose: function (options) {
			if (this.replace) {
				if (options) {
					this.replace.option(options);
				}
				this.replace.close();
			}
		},

		_replaceCreate: function () {
			if (!this.replace) {
				var self = this;

				this.replace = $('<div class="de_epages-presentationUiUploader">')
					.html(tmplUploaderError({}))
					.uiDialog({
						width: 350,
						modal: true,
						autoOpen: false,
						title: tUploaderReplace,
						buttons: {
							replace: {
								text: tReplace,
								click: function () {
									self._replaceClose();
									self._upload({}, true);
								}
							},
							cancel: {
								text: tCancel,
								click: function () {
									self._replaceClose();
									self.statusText = "abort";
									self._uploadComplete();
								}
							}
						}
					})
					.uiDialog('Instance');
			}
		},

		/**
		 * This method removes the container on which the Uploader has been appended to.
		 *
		 * @method destroy
		 * @member jQuery.ui.presentationUiUploader
		 *
		 * @since 6.12.0
		 */
		destroy: function () {
			var self = this;

			if (self.error) {
				self.error.destroy();
			}
			if (self.progress) {
				self.progress.destroy();
			}

			self.custom
				.remove();

			self.elem
				.off('.presentationUiUploader');

			self._superApply(arguments);
		}

	});

	return de_epages;

});