/*
 * bootstrap-FileUpload.js
 * @version: v0.7.0
 * @author: Luke LeBlanc
 *
 * This plugin is very lightweight, highly customizable, easy to use,
 * extremely easy to integrate into any website with minimal dependancies
 * and of course cross compatible. It includes support for mobile devices
 * with fallback options to a regular customized form input field. It has
 * the ability to upload multiple files at once and provide thumbnail
 * previews. All it needs is Twitter Bootstrap V3 and the latest version
 * of jQuery!
 *
 * Copyright (c) 2016 Luke LeBlanc
 *
 * GNU General Public License v3 (http://www.gnu.org/licenses/)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

;(function ($, document, window, undefined) {
	'use strict';

	/**
	 * Array of instances of the plugin
	 * @type Array
	 */
	var instance = {};

	/**
	 * Array of available file types that gets built later on
	 * @type Array
	 */
	var availableFileTypes = {};

	/**
	 * Array of public functions
	 * @type Array
	 */
	var methods = {
		/**
		 * Initializes the plugin
		 * @param  {Array} opts  The array of user modified variables/options
		 * @return {Object}      Runs a loop that starts up the plugin
		 */
		init: function (opts) {
			instance[$(this).attr('id')] = {
				options: $.extend({}, $.fn.bootstrapFileUpload.defaults, opts || {}),
				wrapper: null,
				form: null,
				btnBar: null,
				btnWrapper: null,
				btnAdd: null,
				btnDownload: null,
				btnStart: null,
				btnCancel: null,
				btnReset: null,
				overallProgressBar: null,
				overallStatus: null,
				filePreviewTable: null,
				formData: null,
				arrayFiles: {},
				arrayLength: 0
			};

			return this.each(function () {
				startup($(this).attr('id'));
			});
		},
		/**
		 * Adds file to queue and performs various checks to ensure a proper file was uploaded to spec
		 * @param {Object} el    Current element in loop
		 * @param {Object} event Event object from change event
		 */
		addFile: function (el, event) {
			var screen_id = instance[el].options.screen_id;
			var curfiles = event.target.files;
			var length = curfiles.length;
			var isSuccess = true;
			var trRow = instance[el].wrapper.find('table.fileupload-preview tbody.files tr.row');
			var fileCount = trRow.length;
			var trRowDown = instance[el].wrapper.find('table.fileupload-download tbody tr.row');
			var fileCntDown = trRowDown.length;

			if (instance[el].options.multiFile === false && length > 1 ||
				instance[el].options.multiFile === false && fileCount > 0 ||
				instance[el].options.multiFile === false && fileCntDown > 0) {
				itp_fn_modal_alert_ajax('1' + ITP_MSG_LOCALE.message.upload.fileCnt);
				return;
			}

			if (instance[el].options.multiFile === true && length > instance[el].options.maxFiles ||
				instance[el].options.multiFile === true && instance[el].options.maxFiles < fileCount + length ||
				instance[el].options.multiFile === true && instance[el].options.maxFiles < fileCntDown + length) {
				itp_fn_modal_alert_ajax(instance[el].options.maxFiles + ITP_MSG_LOCALE.message.upload.fileCnt);
				return;
			}

			instance[el].filePreviewTable.detach();
			for (var i = 0; i < length; i++) {
				var fileName, fileExt, fileType, file, size, sizeDisplay, row;

				fileName = screen_id + "-file-" + i;
				file = curfiles[i];
				size = (file.size / 1024) / 1024;
				sizeDisplay = calcFileSize(file.size);
				fileExt = file.name.split('.').pop().toLowerCase();

				if (isValidFileType(el, fileExt) === false) {
					itp_fn_modal_alert_ajax(ITP_MSG_LOCALE.message.upload.fileType);
					isSuccess = false; break;
				}

				fileType = getFileType(el, fileExt);
				if (size.toFixed(2) > instance[el].options.maxSize) {
					itp_fn_modal_alert_ajax(instance[el].options.maxSize + 'MB' + ITP_MSG_LOCALE.message.upload.fileSize);
					isSuccess = false; break;
				}

				var checkFile = function(el, file) {
					var test = [];
					$(trRow).each(function() {
						test.push($(this).find('td.itp_file_info').text());
					});
					return $.inArray(file.name, test);
				}

				//if (instance[el].arrayFiles && checkFile(el, file) >= 0) {
				if (fileCount > 0 && checkFile(el, file) >= 0) {
					itp_fn_modal_alert_ajax(ITP_MSG_LOCALE.message.upload.fileQuene);
					isSuccess = false; break;
				}

				//if (instance[el].arrayLength >= instance[el].options.maxFiles) {
				if (fileCount >= instance[el].options.maxFiles) {
					itp_fn_modal_alert_ajax(instance[el].options.maxFiles + ITP_MSG_LOCALE.message.upload.fileCnt);
					isSuccess = false; break;
				}

				instance[el].arrayFiles[fileName] = file;
				instance[el].arrayLength = ++instance[el].arrayLength;

				var progressBar = '<div class="progress fileupload-progress"><div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%;"></div><div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%;"></div><div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%;"></div></div><div class="alert alert-success"><strong>' + ITP_MSG_LOCALE.message.upload.successUpload + '</strong></div><div class="alert alert-danger"></div>';
				if (instance[el].options.showThumb === true) {
					var thumb = genThumb(el, file, fileType, fileExt);
					if (instance[el].options.multiUpload === false) {
						row = '<tr class="fileupload-previewrow thumb row" id="' + fileName + '"><td class="col-xs-1">' + thumb + '</td><td class="col-xs-4 itp_file_info">' + file.name + '</td><td class="col-xs-2">' + sizeDisplay + '</td><td class="col-xs-5">' + progressBar + '</td><td class="col-xs-1"><button class="btn btn-xs btn-danger fileupload-remove" value="' + fileName + '"><i class="glyphicon glyphicon-ban-circle"></i>&nbsp;<span>' + ITP_MSG_LOCALE.button.delFile + '</span></button></td></tr>';
					}
				} else {
					if (instance[el].options.multiUpload === false) {
						row = '<tr class="fileupload-previewrow no-thumb row" id="' + fileName + '"><td class="col-xs-5 itp_file_info">' + file.name + '</td><td class="col-xs-2">' + sizeDisplay + '</td><td class="col-xs-5">' + progressBar + '</td><td class="col-xs-1"><button class="btn btn-xs btn-danger fileupload-remove" value="' + fileName + '"><i class="glyphicon glyphicon-ban-circle"></i>&nbsp;<span>' + ITP_MSG_LOCALE.button.delFile + '</span></button></td></tr>';
					}
				}
				instance[el].filePreviewTable.append(row);
			}

			instance[el].wrapper.append(instance[el].filePreviewTable);
			instance[el].filePreviewTable.show();

			if (typeof instance[el].options.onFileAdded === 'function' && isSuccess) {
				instance[el].options.onFileAdded.call(this);
			}
		},
		/**
		 * Begins upload process
		 * @param {Object} el Current element in loop
		 */
		uploadStart: function (el) {
			//$(".fileupload-add, .fileupload-start, .fileupload-cancel, .fileupload-remove").attr("disabled", "disabled");
			if (instance[el].options.multiUpload === false) {
				$.each(instance[el].arrayFiles, function (key, value) {
					instance[el].formData = new FormData();
					instance[el].formData.append('uploadFolder', instance[el].options.folderName);
					instance[el].formData.append('fileNo', instance[el].options.fileNumber);
					instance[el].formData.append(instance[el].options.inputName, value, value.name);
					$("#" + key + " .fileupload-progress .progress-bar-striped").show();
					procAjax(el, key);
					if (typeof instance[el].options.onUploadProgress === 'function') {
						instance[el].options.onUploadProgress.call(this);
					}
				});
				//for (var key of instance[el].formData.keys()) {console.log(key);}
				//for (var value of instance[el].formData.values()) {console.log(value);}
			}

			//instance[el].btnAdd.hide();
			//instance[el].btnStart.hide();
			instance[el].btnCancel.hide();
			instance[el].btnDownload.hide();
			//instance[el].btnReset.delay(600).show();

            if (typeof instance[el].options.onUploadComplete === 'function') {
            	instance[el].options.onUploadComplete.call(this);
            }
		},
		/**
		 * Removes file from upload list
		 * @param {Object} el Current element in loop
		 * @param {String} id Id of container
		 */
		removeFile: function (el, id) {
			/*
			if (instance[el].arrayLength <= 1) {
				methods.resetUpload(el);
			} else {
				$("#" + id).hide();
				$("#" + id + " .alert").hide();
				$("#" + id).remove();
				delete instance[el].arrayFiles[id];
				instance[el].arrayLength = --instance[el].arrayLength;
			}
			*/

			var trRow = $("#" + id).children('td.itp_file_info');
			var pFileNo = trRow.attr('data-file-no');
			var pFileNm = trRow.attr('data-file-nm');
			const param = {'fileNo': pFileNo, 'fileNm': pFileNm};
			$("#" + id + " .alert-success").hide();
			$("#" + id + " .alert-danger").hide();
			//console.log(param); return;

			$.ajax({
				contentType: 'application/json',
				url: ITP_CONTEXTPATH + '/deleteFileByNm',
				data: JSON.stringify(param),
		        type: 'POST',
		        dataType: 'json',
		        async: false,
		        timeout: 10000,
		        success: function(result) {
		        	if (result.resultCd == 'E') {
		        		$("#" + id + " .alert-danger").show().html(ITP_MSG_LOCALE.message.upload.fileDelete);
		        	} else {
		        		$("#" + id).hide();
						$("#" + id).remove();
		        	}
		        },
		        error: function(xhr, status, error) {
		        	$("#" + id + " .alert-danger").show().html(ITP_MSG_LOCALE.message.upload.fileDelete);
		        },
		        fail: function() {
		        	$("#" + id + " .alert-danger").show().html(ITP_MSG_LOCALE.message.upload.fileDelete);
		        }
			});

			if (typeof instance[el].options.onFileRemoved === 'function') {
				instance[el].options.onFileRemoved.call(this);
			}
		},
		makeFileDownloadTable: function (fileNum, el) {
			const param = {'fileNo': fileNum, 'useYn': instance[el].options.showYn};
			let href = ITP_CONTEXTPATH + '/selectFileList';
			if (instance[el].options.showThumb === true) {
				href = ITP_CONTEXTPATH + '/selectFileThumb';
			}

			$.ajax({
				contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
				url: href,
				data: $.param(param),
		        type: 'POST',
		        dataType: 'html',
		        async: false,
		        timeout: 10000,
		        success: function(result) {
		        	instance[el].wrapper.append(result);

		        }
			});
		},
		fileDownload: function (el) {
			var trRowDown = instance[el].wrapper.find('table.fileupload-download tbody tr.row');
			var fileCntDown = trRowDown.length;
			if (fileCntDown > 0) {
				var trRow = trRowDown.children('td.itp_file_info').first();
				var pFileNo = trRow.attr('data-file-no');
				var pFileNm = trRow.text();
				var pForder = instance[el].options.folderName;
				const param = {
					'fileNo': pFileNo
					,'fileNm': pFileNm
					,'langCd': ITP_LANGUAGE
					,'fileCnt': fileCntDown
				};
				//console.log(param); return;

				$.ajax({
					contentType: 'application/json',
					url: ITP_CONTEXTPATH + '/makeZipFile',
					data: JSON.stringify(param),
			        type: 'POST',
			        dataType: 'json',
			        async: false,
			        timeout: 10000,
			        success: function(result) {
			        	if (result.resultCd == 'E') {
			        		itp_fn_modal_alert_ajax(ITP_MSG_LOCALE.message.upload.fileDownload);
			        	} else {
			        		//console.log(result.resultData.FILE);
			        		var filePath = result.resultData.FILE.filePath;
			        		var fileOrgNm = result.resultData.FILE.fileOrgNm;
			        		var href = ITP_CONTEXTPATH + '/downloadZipFile?filePath=' + filePath + '&fileOrgNm=' + fileOrgNm;
			        		location.href = encodeURI(href);
			        	}
			        },
			        error: function(xhr, status, error) {
			        	itp_fn_modal_alert_ajax(ITP_MSG_LOCALE.message.upload.fileDownload);
			        },
			        fail: function() {
			        	itp_fn_modal_alert_ajax(ITP_MSG_LOCALE.message.upload.fileDownload);
			        }
				});
			}
		},
		/**
		 * Resets upload list
		 * @param {Object} el Current element in loop
		 */
		resetUpload: function (el) {
			instance[el].filePreviewTable.find("tbody").empty();
			instance[el].form[0].reset();
			instance[el].arrayFiles = {};
			instance[el].arrayLength = 0;

			instance[el].filePreviewTable.hide();
			instance[el].btnStart.hide();
			instance[el].btnCancel.hide();
			$(".fileupload-previewrow .alert").hide();

			$(".fileupload-add, .fileupload-start, .fileupload-cancel").removeAttr("disabled");
			$(".fileupload-add").delay(800).show();

			instance[el].overallProgressBar.find(".progress-bar-success").attr("aria-valuenow", 0).css("width", "0%");

			instance[el].overallProgressBar.hide();
			instance[el].btnReset.hide();

			if (typeof instance[el].options.onUploadReset === 'function') {
				instance[el].options.onUploadReset.call(this);
			}
		}
	};

	/**
	 * Builds the form structure, file types and runs through prerequisite checks
	 * @param {Object} el Current element in loop
	 * @return {Void}
	 */
	function startup (el) {
		instance[el].wrapper = $('#' + el);

		availableFileTypes["archives"] = ["zip", "7z", "gz", "gzip", "rar", "tar"];
		availableFileTypes["audio"] = ["mp3", "wav", "wma", "wpl", "aac", "flac", "m4a", "m4b", "m4p", "midi", "ogg"];
		availableFileTypes["files"] = ["doc", "docx", "dotx", "docm", "ods", "odt", "ott", "ods", "pdf", "ppt", "pptm", "pptx", "pub", "rtf", "csv", "log", "txt", "xls", "xlsm", "xlsx"];
		availableFileTypes["images"] = ["bmp", "tif", "tiff", "gif", "jpeg", "jpg", "png", "svg", "ico", "raw"];
		availableFileTypes["video"] = ["avi", "flv", "swf", "m4v", "mkv", "mov", "mp4", "ogv", "wmv"];

		buildFileTypes(el);

		if (instance[el].options.debug !== true && instance[el].options.debug !== false) {
			instance[el].options.debug = false;
		}

		if (typeof $().emulateTransitionEnd !== 'function') {
			debug(el, "bootstrap");
			return;
		}

		if (instance[el].options.showThumb === true && instance[el].options.useFontAwesome === true) {
			if (!$("link[href*='fontawesome']").length && !$("link[href*='font-awesome']").length) {
				debug(el, "fontAwesome");
				return;
			} else {
				if (checkFontAwesomeVer(el) === false) {
					debug(el, "fontAwesomeVersion");
					return;
				}
			}
		}

		if (instance[el].options.url === null || !isUrlValid(instance[el].options.url)) {
			debug(el, "url");
			return;
		}

		if (instance[el].options.formMethod !== 'post' && instance[el].options.formMethod !== 'get') {
			debug(el, "formMethod");
			return;
		}

		if (instance[el].options.fallbackUrl !== null && !isUrlValid(instance[el].options.fallbackUrl)) {
			debug(el, "fallbackUrl");
			return;
		}

		if (testBrowser && instance[el].options.forceFallback === false) {
			formStructure(el);
		} else {
			fallbackFormStructure(el);
		}

		if (typeof instance[el].options.onInit === 'function') {
			instance[el].options.onInit.call(this);
		}
	}

	/**
	 * Builds the file type array used to validate file types being uploaded
	 * @param {Object} el Current element in loop
	 * @return {Void}
	 */
	function buildFileTypes (el) {
		$.each(instance[el].options.fileTypes, function (key, value) {
			if ($.isNumeric(key)) {
				instance[el].options.fileTypes[value] = availableFileTypes[value];
			} else if (!$.isNumeric(key) && $.isEmptyObject(value)) {
				instance[el].options.fileTypes[key] = availableFileTypes[key];
			}
		});

		return;
	}

	/**
	 * Creates an invisible test span with the fa class and verifies what the version is based on the font family
	 * @param  {Object} el Current element in loop
	 * @return {Boolean}
	 */
	function checkFontAwesomeVer (el) {
		var faSpan, faFontFamily;

		faSpan = $('<span class="fa" style="display:none"></span>').appendTo('body');
		faFontFamily = faSpan.css('fontFamily');
		faSpan.remove();

        if (faFontFamily === 'FontAwesome' ) {
            instance[el].options.fontAwesomeVer = 4;
        } else if (faFontFamily.indexOf('Font Awesome 5') !== -1) {
			instance[el].options.fontAwesomeVer = 5;
        } else {
        	return false;
        }

        return true;
	}

	/**
	 * Assigns an error message based on the type passed and either sends error to console or to screen
	 * @param {Object} el   Current element in loop
	 * @param {String} type Error type
	 */
	function debug (el, type) {
		var alertMsg, alertWrapper = $('<div class="alert alert-danger" role="alert"></div>');

		switch (type) {
			case 'method':
				alertMsg = "The passed method " + name + " is not a valid method. Please check the configuration.";

				break;
			case 'fontAwesome':
				alertMsg = "The Font Awesome CSS is not available within the head of the website and is a required unless the option showThumb is set to false.";

				break;
			case 'fontAwesomeVersion':
				alertMsg = "The Font Awesome version could not be detected. Please set manually with the fontAwesomeVer option.";

				break;
			case 'url':
				alertMsg = "The URL provided in the configuration is not a valid URL.";

				break;
			case 'fallbackUrl':
				alertMsg = "The Fallback URL provided in the configuration is not a valid URL.";

				break;
			case 'formMethod':
				alertMsg = "The Form Method provided in the configuration is not a valid, please choose either get or post in the configuration.";

				break;
			case 'bootstrap':
				alertMsg = "The Twitter Bootstrap API is not available on the current page. Please check to make sure all the dependencies are in place.";

				break;
			default:
				alertMsg = "An unknown error occured.";

				break;
		}

		if (instance[el].options.debug === false && (window.console && window.console.error)) {
			window.console.error(alertMsg);
		} else if (instance[el].options.debug === true) {
			alertWrapper.append(alertMsg);
			instance[el].wrapper.append(alertWrapper);
		}
	}

	/**
	 * Basic check to ensure url is valid
	 * @param  {String}  url Url being validated
	 * @return {Boolean}
	 */
	function isUrlValid (url) {
		return true;
		//return /((http(s)?|ftp(s)?):\/\/)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&amp;:\/~+#-]*[\w@?^=%&amp;\/~+#-])?/.test(url);
	}

	/**
	 * Tests browser to ensure it supports use of xhr upload/onprogress
	 * @return {Boolean}
	 */
	function testBrowser () {
		var xhr = new XMLHttpRequest();
		return !! (window.FormData && xhr && ('upload' in xhr) && ('onprogress' in xhr.upload));
	}

	/**
	 * Builds plugin form structure using bootstrap
	 * @param {Object} el Current element in loop
	 */
	function formStructure (el) {
		instance[el].form = $('<form id="' + instance[el].options.screen_id + '_UPLOAD_FORM" method="' + instance[el].options.formMethod + '" enctype="multipart/form-data"></form>');
		instance[el].btnBar = $('<div class="row fileupload-buttonbar"></div>');
		instance[el].btnWrapper = $('<div class="col-xs-12"></div>');

		instance[el].btnAdd = $('<div class="btn btn-sm btn-success fileupload-add"><input type="file" ' + (instance[el].options.multiFile === true ? 'multiple="multiple"' : '') + ' /><i class="glyphicon glyphicon-plus"></i>&nbsp;' + ITP_MSG_LOCALE.button.addFile + '</div>');
		instance[el].btnReset = $('<button type="reset" class="btn btn-sm btn-primary fileupload-reset"><i class="glyphicon glyphicon-repeat"></i>&nbsp;' + ITP_MSG_LOCALE.button.editFile + '</button>');
		instance[el].btnStart = $('<button class="btn btn-sm btn-warning fileupload-start"><i class="glyphicon glyphicon-upload"></i>&nbsp;<span>' + ITP_MSG_LOCALE.button.startUpload + '</span></button>');
		instance[el].btnCancel = $('<button type="reset" class="btn btn-sm btn-danger fileupload-cancel"><i class="glyphicon glyphicon-ban-circle"></i>&nbsp;<span>' + ITP_MSG_LOCALE.button.cancelUpload + '</span></button>');
		instance[el].btnDownload = $('<button class="btn btn-sm btn-warning fileupload-down"><i class="glyphicon glyphicon-download-alt"></i>&nbsp;<span>' + ITP_MSG_LOCALE.button.download + '</span></button>');
		instance[el].overallProgressBar = $('<div class="col-xs-12 fileupload-overall-progress"><div class="progress"><div class="progress-bar progress-striped active" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%;"></div><div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%;"></div><div class="progress-extended">&nbsp;</div></div></div>');
		instance[el].overallStatus = $('<div class="row fileupload-overall-status"><div class="col-xs-12"><div class="alert alert-success"><strong>' + ITP_MSG_LOCALE.message.upload.successUpload + '</strong></div><div class="alert alert-danger"></div></div></div>');
		instance[el].filePreviewTable = $('<table role="presentation" class="table table-striped fileupload-preview"><tbody class="files"></tbody></table>');

		instance[el].btnWrapper.append(instance[el].btnAdd, instance[el].btnReset, instance[el].btnStart, instance[el].btnCancel, instance[el].btnDownload);
		instance[el].btnBar.append(instance[el].btnWrapper, instance[el].overallProgressBar);
		instance[el].form.append(instance[el].folder, instance[el].btnBar, instance[el].overallStatus);
		instance[el].wrapper.append(instance[el].form, instance[el].filePreviewTable);

		if (instance[el].options.viewCode == 'C' || instance[el].options.showThumb === true) {
			instance[el].btnDownload.hide();
		} else {
			instance[el].btnDownload.show();
			methods.makeFileDownloadTable(instance[el].options.fileNumber, el);
		}

		if (instance[el].options.showYn == 'Y') {
			instance[el].btnAdd.show();
		} else {
			instance[el].btnAdd.hide();
		}

		instance[el].btnAdd.on('change', 'input', function (e) {
			methods.addFile(el, e);
		});

		instance[el].btnReset.on('click', function (e) {
			e.preventDefault();
			methods.resetUpload(el);
		});

		instance[el].btnStart.on('click', function (e) {
			e.preventDefault();
			methods.uploadStart(el);
		});

		instance[el].btnCancel.on('click', function () {
			methods.resetUpload(el);
		});

		instance[el].btnDownload.on('click', function (e) {
			e.preventDefault();
			methods.fileDownload(el);
		});

		instance[el].filePreviewTable.on('click', '.fileupload-remove', function () {
			methods.removeFile(el, $(this).val());
		});
	}

	/**
	 * Builds fallback form structure without use of bootstrap
	 * @param {Object} el Current element in loop
	 */
	function fallbackFormStructure (el) {
		instance[el].form = $('<form action="' + (instance[el].options.fallbackUrl ? instance[el].options.fallbackUrl : instance[el].options.url) + '" method="' + instance[el].options.formMethod + '" enctype="multipart/form-data"></form>');
		instance[el].btnAdd = $('<div class="input-group"><span class="input-group-btn"><span class="btn btn-sm btn-success fileupload-fallback-add"><i class="glyphicon glyphicon-plus"></i>&nbsp;Add Files&hellip; <input type="file" name="' + instance[el].options.inputName + '" ' + (instance[el].options.multiFile === true ? 'multiple="multiple"' : '') + '></span></span><input type="text" class="form-control" readonly></div>');
		instance[el].btnStart = $('<div class="form-group"><button type="submit" class="btn btn-sm btn-warning fileupload-fallback-start"><i class="glyphicon glyphicon-upload"></i>&nbsp;<span>' + ITP_MSG_LOCALE.button.startUpload + '</span></button><button type="reset" class="btn btn-sm btn-primary fileupload-fallback-reset"><i class="glyphicon glyphicon-repeat"></i>&nbsp;Reset</button></div>');

		instance[el].form.append(instance[el].btnAdd, instance[el].btnStart);
		instance[el].wrapper.append(instance[el].form);

		instance[el].btnAdd.on('change', '.fileupload-fallback-add input[type=file]', function () {
			var input, numFiles, label;
			input = $(this);
			numFiles = input.get(0).files ? input.get(0).files.length : 1;
			label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
			input.trigger('fileselect', [numFiles, label]);
		});

		instance[el].btnAdd.find(".fileupload-fallback-add input[type=file]").on('fileselect', function (e, numFiles, label) {
			var input, log;
			input = $(this).parents('.input-group').find('input[type=text]');
			log = numFiles > 1 ? numFiles + ' files selected' : label;
			if (input.length) {
				input.val(log);
			}
        });
	}

	/**
	 * Calculates a human readable file size from bytes
	 * @param  {Integar} size    Actual file size
	 * @return {String}
	 */
	function calcFileSize(size) {
	    var i = (size === 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024)));

	    return (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'KB', 'MB', 'GB', 'TB'][i];
	}

	/**
	 * Ensures the file being uploaded has an approved file extension
	 * @param  {Object}  el      Current element in loop
	 * @param  {String}  fileExt The file extension being checked
	 * @return {Boolean}
	 */
	function isValidFileType (el, fileExt) {
		var result = false;

		$.each(instance[el].options.fileTypes, function (type, extensions) {
			if ($.inArray(fileExt, extensions) >= 0) {
				result = true;

				return false;
			}
		});

		return result;
	}

	/**
	 * Gets the file type based on the file extension matched up with the approved file types
	 * @param  {Object} el      Current element in loop
	 * @param  {String} fileExt File extension being checked
	 * @return {Boolean/String}
	 */
	function getFileType (el, fileExt) {
		var fileType;

		$.each(instance[el].options.fileTypes, function (type, extensions) {
			if ($.inArray(fileExt, extensions) >= 0) {
				fileType = type;

				return false;
			}
		});

		return fileType;
	}

	/**
	 * Checks if file is valid
	 * @param  {Object} el   Current element in loop
	 * @param  {Object} file File being tested for upload
	 * @return {Boolean}
	 */
	function checkFile(el, file) {
		var test = [];
		$.each(instance[el].arrayFiles, function (key, value) {
			test.push(value.name);
		});
		return $.inArray(file.name, test);
	}

	/**
	 * Generates a thumbnail of the file to be used as a preview when uploading - uses FontAwesome if the file isn't an image
	 * @param  {Object} el       Current element in loop
	 * @param  {Object} file     File used to generate thumbnail
	 * @param  {String} fileType The type of file matched with the approved uploadable file types
	 * @param  {String} fileExt  File extension of the file
	 * @return {Object}
	 */
	function genThumb (el, file, fileType, fileExt) {
		var thumb;

		switch (fileType) {
			case 'archives':
				if (instance[el].options.useFontAwesome === true && instance[el].options.fontAwesomeVer !== false) {
					thumb = '<i class="' + (instance[el].options.fontAwesomeVer >= 5 ? "far fa-file-archive" : "fa fa-file-archive-o") + ' fa-5x"></i>';
				} else {
					thumb = '';
				}

				break;
			case 'audio':
				if (instance[el].options.useFontAwesome === true && instance[el].options.fontAwesomeVer !== false) {
					thumb = '<i class="' + (instance[el].options.fontAwesomeVer >= 5 ? "far fa-file-audio" : "fa fa-file-audio-o") + ' fa-5x"></i>';
				} else {
					thumb = '';
				}

				break;
			case 'files':
				switch (fileExt) {
					case 'doc':
					case 'docx':
					case 'dotx':
					case 'docm':
						if (instance[el].options.useFontAwesome === true && instance[el].options.fontAwesomeVer !== false) {
							thumb = '<i class="' + (instance[el].options.fontAwesomeVer >= 5 ? "fas fa-file-word" : "fa fa-file-word-o") + ' fa-5x"></i>';
						} else {
							thumb = '';
						}

						break;
					case 'ppt':
					case 'pptm':
					case 'pptx':
						if (instance[el].options.useFontAwesome === true && instance[el].options.fontAwesomeVer !== false) {
							thumb = '<i class="' + (instance[el].options.fontAwesomeVer >= 5 ? "fas fa-file-powerpoint" : "fa fa-file-powerpoint-o") + ' fa-5x"></i>';
						} else {
							thumb = '';
						}

						break;
					case 'pdf':
						if (instance[el].options.useFontAwesome === true && instance[el].options.fontAwesomeVer !== false) {
							thumb = '<i class="' + (instance[el].options.fontAwesomeVer >= 5 ? "fas fa-file-pdf" : "fa fa-file-pdf-o") + ' fa-5x"></i>';
						} else {
							thumb = '';
						}

						break;
					case 'xls':
					case 'csv':
					case 'xlsm':
					case 'xlsx':
						if (instance[el].options.useFontAwesome === true && instance[el].options.fontAwesomeVer !== false) {
							thumb = '<i class="' + (instance[el].options.fontAwesomeVer >= 5 ? "fas fa-file-excel" : "fa fa-file-excel-o") + ' fa-5x"></i>';
						} else {
							thumb = '';
						}

						break;
					default:
						if (instance[el].options.useFontAwesome === true && instance[el].options.fontAwesomeVer !== false) {
							thumb = '<i class="' + (instance[el].options.fontAwesomeVer >= 5 ? "fas fa-file" : "fa fa-file-o") + ' fa-5x"></i>';
						} else {
							thumb = '';
						}

						break;
				}

				break;
			case 'images':
				thumb = '<img src="' + URL.createObjectURL(file) + '" alt="' + file.name + '" width="' + instance[el].options.thumbWidth + 'px" height="' + instance[el].options.thumbHeight + 'px" class="fileupload-previewimg" />';

				break;
			case 'video':
				if (instance[el].options.useFontAwesome === true && instance[el].options.fontAwesomeVer !== false) {
					thumb = '<i class="' + (instance[el].options.fontAwesomeVer >= 5 ? "fas fa-file-video" : "fa fa-file-video-o") + ' fa-5x"></i>';
				} else {
					thumb = '';
				}

				break;
		}

		return thumb;
	}

	/**
	 * Processes the file upload via ajax - updates progress bar as it uploads
	 * @param  {Object} el  Current element in loop
	 * @param  {String} key Id of the row of the file being uploaded
	 * @return {Object}
	 */
	function procAjax (el, key) {
		$.ajax({
			url: instance[el].options.url,
			type: instance[el].options.formMethod,
			data: instance[el].formData,
			enctype: 'multipart/form-data',
			cache: false,
			contentType: false,
			processData: false,
			success: function(result, status, xhr) {
				if (result.resultCd == 'E') {
					if (instance[el].options.multiUpload === false) {
						$("#" + key + " .fileupload-progress .progress-bar-striped").attr("aria-valuenow", 0).css("width", "0%");
						$("#" + key + " .fileupload-progress .progress-bar-danger").attr("aria-valuenow", 100).css("width", "100%");
						$("#" + key + " .alert-danger").show().html(ITP_MSG_LOCALE.message.upload.failUpload);
					}
					if (typeof instance[el].options.onUploadError === 'function') {
						instance[el].options.onUploadError.call(this);
					}
				} else {
					if (instance[el].options.multiUpload === false) {
						$("#" + key + " .fileupload-progress .progress-bar-striped").attr("aria-valuenow", 0).css("width", "0%");
						$("#" + key + " .fileupload-progress .progress-bar-success").attr("aria-valuenow", 100).css("width", "100%");
						$("#" + key + " .alert-success").show();
						$("#" + key + " .alert-danger").hide();
						$("#" + key + " .itp_file_info").attr('data-file-no', result.resultData.FILE[0].fileNo);
						$("#" + key + " .itp_file_info").attr('data-file-nm', result.resultData.FILE[0].fileNm);
					}
					if (typeof instance[el].options.onUploadSuccess === 'function') {
						instance[el].options.onUploadSuccess.call(this);
					}
				}

				instance[el].form[0].reset();
				instance[el].arrayFiles = {};
				instance[el].arrayLength = 0;
			},
			error: function (xhr, status, err) {
				if (instance[el].options.multiUpload === false) {
					$("#" + key + " .fileupload-progress .progress-bar-striped").attr("aria-valuenow", 0).css("width", "0%");
					$("#" + key + " .fileupload-progress .progress-bar-danger").attr("aria-valuenow", 100).css("width", "100%");
					$("#" + key + " .alert-danger").show().html(ITP_MSG_LOCALE.message.upload.failUpload);
				}
				if (typeof instance[el].options.onUploadError === 'function') {
					instance[el].options.onUploadError.call(this);
				}

				instance[el].form[0].reset();
				instance[el].arrayFiles = {};
				instance[el].arrayLength = 0;
			},
			xhr: function () {
				var myXhr = $.ajaxSettings.xhr();
				if (myXhr.upload) {
					myXhr.upload.addEventListener('progress', function (e) {
						if (e.lengthComputable) {
							var percentComplete = e.loaded / e.total;
							if (instance[el].options.multiUpload === false) {
								$("#" + key + " .fileupload-progress .progress-bar-striped").attr("aria-valuenow", Math.round(percentComplete * 100)).css("width", Math.round(percentComplete * 100) + "%");
							}
							if (typeof instance[el].options.onUploadProgress === 'function') {
								instance[el].options.onUploadProgress.call(this);
							}
						}
					});
				}

				instance[el].form[0].reset();
				instance[el].arrayFiles = {};
				instance[el].arrayLength = 0;
				return myXhr;
			}
		});
	}

	/**
	 * Method handler
	 * @param  {Object/Function} method The method function being used
	 */
	$.bootstrapFileUpload = $.fn.bootstrapFileUpload = function (method) {
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method === 'object' || !method) {
			methods.init.apply(this, arguments);
		} else {
			window.console.error("The passed method " + method + " is not a valid method. Please check the configuration.");
		}
	};

	/**
	 * Default options for the plugin
	 * @type {Object}
	 */
	$.fn.bootstrapFileUpload.defaults = {
		url: null,
		fallbackUrl: null,
		formMethod: 'post',
		multiFile: true,
		multiUpload: false,
		inputName: 'files',
		folderName: null,
		fileNumber: null,
		viewCode: null,
		forceFallback: false,
		maxSize: 5,
		maxFiles: null,
		showThumb: true,
		useFontAwesome: false,
		fontAwesomeVer: false,
		thumbWidth: 80,
		thumbHeight: 80,
		screen_id: null,
		showYn: null,
		fileTypes: {
			archives: [],
			audio: [],
			files: [],
			images: [],
			video: []
		},
		debug: false,
		onInit: function () {},
		onFileAdded: function () {},
		onFileRemoved: function () {},
		onFileCancel: function () {},
		onFileProcessing: function () {},
		onUploadProgress: function () {},
		onUploadError: function () {},
		onUploadSuccess: function () {},
		onUploadComplete: function () {},
		onUploadReset: function () {}
	};
}(jQuery, document, window));