text: /**
   * FilePicker.js
   *
   * Released under LGPL License.
   * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
   *
   * License: http://www.tinymce.com/license
   * Contributing: http://www.tinymce.com/contributing
   */
  
  /*global tinymce:true */
  
  /**
   * This class creates a file picker control.
   *
   * @class tinymce.ui.FilePicker
   * @extends tinymce.ui.ComboBox
   */
  define("tinymce/ui/FilePicker", [
  	"tinymce/ui/ComboBox",
  	"tinymce/util/Tools",
  	"tinymce/util/Arr",
  	"tinymce/util/Fun",
  	"tinymce/util/VK",
  	"tinymce/content/LinkTargets"
  ], function(ComboBox, Tools, Arr, Fun, VK, LinkTargets) {
  	"use strict";
  
  	var history = {};
  	var HISTORY_LENGTH = 5;
  
  	var toMenuItem = function (target) {
  		return {
  			title: target.title,
  			value: {
  				title: {raw: target.title},
  				url: target.url,
  				attach: target.attach
  			}
  		};
  	};
  
  	var toMenuItems = function (targets) {
  		return Tools.map(targets, toMenuItem);
  	};
  
  	var staticMenuItem = function (title, url) {
  		return {
  			title: title,
  			value: {
  				title: title,
  				url: url,
  				attach: Fun.noop
  			}
  		};
  	};
  
  	var isUniqueUrl = function (url, targets) {
  		var foundTarget = Arr.find(targets, function (target) {
  			return target.url === url;
  		});
  
  		return !foundTarget;
  	};
  
  	var getSetting = function (editorSettings, name, defaultValue) {
  		var value = name in editorSettings ? editorSettings[name] : defaultValue;
  		return value === false ? null : value;
  	};
  
  	var createMenuItems = function (term, targets, fileType, editorSettings) {
  		var separator = {title: '-'};
  
  		var fromHistoryMenuItems = function (history) {
  			var uniqueHistory = Arr.filter(history[fileType], function (url) {
  				return isUniqueUrl(url, targets);
  			});
  
  			return Tools.map(uniqueHistory, function (url) {
  				return {
  					title: url,
  					value: {
  						title: url,
  						url: url,
  						attach: Fun.noop
  					}
  				};
  			});
  		};
  
  		var fromMenuItems = function (type) {
  			var filteredTargets = Arr.filter(targets, function (target) {
  				return target.type == type;
  			});
  
  			return toMenuItems(filteredTargets);
  		};
  
  		var anchorMenuItems = function () {
  			var anchorMenuItems = fromMenuItems('anchor');
  			var topAnchor = getSetting(editorSettings, 'anchor_top', '#top');
  			var bottomAchor = getSetting(editorSettings, 'anchor_bottom', '#bottom');
  
  			if (topAnchor !== null) {
  				anchorMenuItems.unshift(staticMenuItem('<top>', topAnchor));
  			}
  
  			if (bottomAchor !== null) {
  				anchorMenuItems.push(staticMenuItem('<bottom>', bottomAchor));
  			}
  
  			return anchorMenuItems;
  		};
  
  		var join = function (items) {
  			return Arr.reduce(items, function (a, b) {
  				var bothEmpty = a.length === 0 || b.length === 0;
  				return bothEmpty ? a.concat(b) : a.concat(separator, b);
  			}, []);
  		};
  
  		if (editorSettings.typeahead_urls === false) {
  			return [];
  		}
  
  		return fileType === 'file' ? join([
  			filterByQuery(term, fromHistoryMenuItems(history)),
  			filterByQuery(term, fromMenuItems('header')),
  			filterByQuery(term, anchorMenuItems())
  		]) : filterByQuery(term, fromHistoryMenuItems(history));
  	};
  
  	var addToHistory = function (url, fileType) {
  		var items = history[fileType];
  
  		if (!/^https?/.test(url)) {
  			return;
  		}
  
  		if (items) {
  			if (Arr.indexOf(items, url) === -1) {
  				history[fileType] = items.slice(0, HISTORY_LENGTH).concat(url);
  			}
  		} else {
  			history[fileType] = [url];
  		}
  	};
  
  	var filterByQuery = function (term, menuItems) {
  		var lowerCaseTerm = term.toLowerCase();
  		var result = Tools.grep(menuItems, function (item) {
  			return item.title.toLowerCase().indexOf(lowerCaseTerm) !== -1;
  		});
  
  		return result.length === 1 && result[0].title === term ? [] : result;
  	};
  
  	var getTitle = function (linkDetails) {
  		var title = linkDetails.title;
  		return title.raw ? title.raw : title;
  	};
  
  	var setupAutoCompleteHandler = function (ctrl, editorSettings, bodyElm, fileType) {
  		var autocomplete = function (term) {
  			var linkTargets = LinkTargets.find(bodyElm);
  			var menuItems = createMenuItems(term, linkTargets, fileType, editorSettings);
  			ctrl.showAutoComplete(menuItems, term);
  		};
  
  		ctrl.on('autocomplete', function () {
  			autocomplete(ctrl.value());
  		});
  
  		ctrl.on('selectitem', function (e) {
  			var linkDetails = e.value;
  
  			ctrl.value(linkDetails.url);
  			var title = getTitle(linkDetails);
  
  			if (fileType === 'image') {
  				ctrl.fire('change', {meta: {alt: title, attach: linkDetails.attach}});
  			} else {
  				ctrl.fire('change', {meta: {text: title, attach: linkDetails.attach}});
  			}
  
  			ctrl.focus();
  		});
  
  		ctrl.on('click', function (e) {
  			if (ctrl.value().length === 0 && e.target.nodeName === 'INPUT') {
  				autocomplete('');
  			}
  		});
  
  		ctrl.on('PostRender', function () {
  			ctrl.getRoot().on('submit', function (e) {
  				if (!e.isDefaultPrevented()) {
  					addToHistory(ctrl.value(), fileType);
  				}
  			});
  		});
  	};
  
  	var statusToUiState = function (result) {
  		var status = result.status, message = result.message;
  
  		if (status === 'valid') {
  			return {status: 'ok', message: message};
  		} else if (status === 'unknown') {
  			return {status: 'warn', message: message};
  		} else if (status === 'invalid') {
  			return {status: 'warn', message: message};
  		} else {
  			return {status: 'none', message: ''};
  		}
  	};
  
  	var setupLinkValidatorHandler = function (ctrl, editorSettings, fileType) {
  		var validatorHandler = editorSettings.filepicker_validator_handler;
  		if (validatorHandler) {
  			var validateUrl = function (url) {
  				if (url.length === 0) {
  					ctrl.statusLevel('none');
  					return;
  				}
  
  				validatorHandler({
  					url: url,
  					type: fileType
  				}, function (result) {
  					var uiState = statusToUiState(result);
  
  					ctrl.statusMessage(uiState.message);
  					ctrl.statusLevel(uiState.status);
  				});
  			};
  
  			ctrl.state.on('change:value', function (e) {
  				validateUrl(e.value);
  			});
  		}
  	};
  
  	return ComboBox.extend({
  		/**
  		 * Constructs a new control instance with the specified settings.
  		 *
  		 * @constructor
  		 * @param {Object} settings Name/value object with settings.
  		 */
  		init: function(settings) {
  			var self = this, editor = tinymce.activeEditor, editorSettings = editor.settings;
  			var actionCallback, fileBrowserCallback, fileBrowserCallbackTypes;
  			var fileType = settings.filetype;
  
  			settings.spellcheck = false;
  
  			fileBrowserCallbackTypes = editorSettings.file_picker_types || editorSettings.file_browser_callback_types;
  			if (fileBrowserCallbackTypes) {
  				fileBrowserCallbackTypes = Tools.makeMap(fileBrowserCallbackTypes, /[, ]/);
  			}
  
  			if (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType]) {
  				fileBrowserCallback = editorSettings.file_picker_callback;
  				if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
  					actionCallback = function() {
  						var meta = self.fire('beforecall').meta;
  
  						meta = Tools.extend({filetype: fileType}, meta);
  
  						// file_picker_callback(callback, currentValue, metaData)
  						fileBrowserCallback.call(
  							editor,
  							function(value, meta) {
  								self.value(value).fire('change', {meta: meta});
  							},
  							self.value(),
  							meta
  						);
  					};
  				} else {
  					// Legacy callback: file_picker_callback(id, currentValue, filetype, window)
  					fileBrowserCallback = editorSettings.file_browser_callback;
  					if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
  						actionCallback = function() {
  							fileBrowserCallback(
  								self.getEl('inp').id,
  								self.value(),
  								fileType,
  								window
  							);
  						};
  					}
  				}
  			}
  
  			if (actionCallback) {
  				settings.icon = 'browse';
  				settings.onaction = actionCallback;
  			}
  
  			self._super(settings);
  
  			setupAutoCompleteHandler(self, editorSettings, editor.getBody(), fileType);
  			setupLinkValidatorHandler(self, editorSettings, fileType);
  		}
  	});
  });