text: /**
   * Plugin.js
   *
   * Released under LGPL License.
   * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
   *
   * License: http://www.tinymce.com/license
   * Contributing: http://www.tinymce.com/contributing
   */
  
  /**
   *
   * Settings:
   *  imagetools_cors_hosts - Array of remote domains that has CORS setup.
   *  imagetools_proxy - Url to proxy that streams Images from remote host to local host.
   *  imagetools_toolbar - Toolbar items to render when an editable image is selected.
   */
  define("tinymce/imagetoolsplugin/Plugin", [
  	"global!tinymce.PluginManager",
  	"global!tinymce.Env",
  	"global!tinymce.util.Promise",
  	"global!tinymce.util.URI",
  	"global!tinymce.util.Tools",
  	"global!tinymce.util.Delay",
  	"ephox/imagetools/api/ImageTransformations",
  	"ephox/imagetools/api/BlobConversions",
  	"tinymce/imagetoolsplugin/Dialog",
  	"tinymce/imagetoolsplugin/ImageSize",
  	"tinymce/imagetoolsplugin/Proxy"
  ], function(PluginManager, Env, Promise, URI, Tools, Delay, ImageTransformations, BlobConversions, Dialog, ImageSize, Proxy) {
  	var plugin = function(editor) {
  		var count = 0, imageUploadTimer, lastSelectedImage;
  
  		if (!Env.fileApi) {
  			return;
  		}
  
  		function displayError(error) {
  			editor.notificationManager.open({
  				text: error,
  				type: 'error'
  			});
  		}
  
  		function getSelectedImage() {
  			return editor.selection.getNode();
  		}
  
  		function createId() {
  			return 'imagetools' + count++;
  		}
  
  		function isLocalImage(img) {
  			var url = img.src;
  
  			return url.indexOf('data:') === 0 || url.indexOf('blob:') === 0 || new URI(url).host === editor.documentBaseURI.host;
  		}
  
  		function isCorsImage(img) {
  			return Tools.inArray(editor.settings.imagetools_cors_hosts, new URI(img.src).host) !== -1;
  		}
  
  		function getApiKey() {
  			return editor.settings.api_key || editor.settings.imagetools_api_key;
  		}
  
  		function imageToBlob(img) {
  			var src = img.src, apiKey;
  
  			if (isCorsImage(img)) {
  				return Proxy.getUrl(img.src, null);
  			}
  
  			if (!isLocalImage(img)) {
  				src = editor.settings.imagetools_proxy;
  				src += (src.indexOf('?') === -1 ? '?' : '&') + 'url=' + encodeURIComponent(img.src);
  				apiKey = getApiKey();
  				return Proxy.getUrl(src, apiKey);
  			}
  
  			return BlobConversions.imageToBlob(img);
  		}
  
  		function findSelectedBlob() {
  			var blobInfo;
  
  			blobInfo = editor.editorUpload.blobCache.getByUri(getSelectedImage().src);
  			if (blobInfo) {
  				return blobInfo.blob();
  			}
  
  			return imageToBlob(getSelectedImage());
  		}
  
  		function startTimedUpload() {
  			imageUploadTimer = Delay.setEditorTimeout(editor, function() {
  				editor.editorUpload.uploadImagesAuto();
  			}, 30000);
  		}
  
  		function cancelTimedUpload() {
  			clearTimeout(imageUploadTimer);
  		}
  
  		function updateSelectedImage(blob, uploadImmediately) {
  			return BlobConversions.blobToDataUri(blob).then(function(dataUri) {
  				var id, base64, blobCache, blobInfo, selectedImage;
  
  				selectedImage = getSelectedImage();
  				id = createId();
  				blobCache = editor.editorUpload.blobCache;
  				base64 = URI.parseDataUri(dataUri).data;
  
  				blobInfo = blobCache.create(id, blob, base64);
  				blobCache.add(blobInfo);
  
  				editor.undoManager.transact(function() {
  					function imageLoadedHandler() {
  						editor.$(selectedImage).off('load', imageLoadedHandler);
  						editor.nodeChanged();
  
  						if (uploadImmediately) {
  							editor.editorUpload.uploadImagesAuto();
  						} else {
  							cancelTimedUpload();
  							startTimedUpload();
  						}
  					}
  
  					editor.$(selectedImage).on('load', imageLoadedHandler);
  
  					editor.$(selectedImage).attr({
  						src: blobInfo.blobUri()
  					}).removeAttr('data-mce-src');
  				});
  
  				return blobInfo;
  			});
  		}
  
  		function selectedImageOperation(fn) {
  			return function() {
  				return editor._scanForImages().then(findSelectedBlob).then(fn).then(updateSelectedImage, displayError);
  			};
  		}
  
  		function rotate(angle) {
  			return function() {
  				return selectedImageOperation(function(blob) {
  					var size = ImageSize.getImageSize(getSelectedImage());
  
  					if (size) {
  						ImageSize.setImageSize(getSelectedImage(), {
  							w: size.h,
  							h: size.w
  						});
  					}
  
  					return ImageTransformations.rotate(blob, angle);
  				})();
  			};
  		}
  
  		function flip(axis) {
  			return function() {
  				return selectedImageOperation(function(blob) {
  					return ImageTransformations.flip(blob, axis);
  				})();
  			};
  		}
  
  		function editImageDialog() {
  			var img = getSelectedImage(), originalSize = ImageSize.getNaturalImageSize(img);
  			var handleDialogBlob = function(blob) {
  				return new Promise(function(resolve) {
  					BlobConversions.blobToImage(blob).then(function(newImage) {
  						var newSize = ImageSize.getNaturalImageSize(newImage);
  
  						if (originalSize.w != newSize.w || originalSize.h != newSize.h) {
  							if (ImageSize.getImageSize(img)) {
  								ImageSize.setImageSize(img, newSize);
  							}
  						}
  
  						URL.revokeObjectURL(newImage.src);
  						resolve(blob);
  					});
  				});
  			};
  
  			var openDialog = function (blob) {
  				return Dialog.edit(blob).then(handleDialogBlob).then(function(blob) {
  					updateSelectedImage(blob, true);
  				}, function () {
  					// Close dialog
  				});
  			};
  
  			if (img) {
  				imageToBlob(img).then(openDialog, displayError);
  			}
  		}
  
  		function addButtons() {
  			editor.addButton('rotateleft', {
  				title: 'Rotate counterclockwise',
  				onclick: rotate(-90)
  			});
  
  			editor.addButton('rotateright', {
  				title: 'Rotate clockwise',
  				onclick: rotate(90)
  			});
  
  			editor.addButton('flipv', {
  				title: 'Flip vertically',
  				onclick: flip('v')
  			});
  
  			editor.addButton('fliph', {
  				title: 'Flip horizontally',
  				onclick: flip('h')
  			});
  
  			editor.addButton('editimage', {
  				title: 'Edit image',
  				onclick: editImageDialog
  			});
  
  			editor.addButton('imageoptions', {
  				title: 'Image options',
  				icon: 'options',
  				cmd: 'mceImage'
  			});
  
  			/*
  			editor.addButton('crop', {
  				title: 'Crop',
  				onclick: startCrop
  			});
  			*/
  		}
  
  		function addEvents() {
  			editor.on('NodeChange', function(e) {
  				//If the last node we selected was an image
  				//And had a source that doesn't match the current blob url
  				//We need to attempt to upload it
  				if (lastSelectedImage && lastSelectedImage.src != e.element.src) {
  					cancelTimedUpload();
  					editor.editorUpload.uploadImagesAuto();
  					lastSelectedImage = undefined;
  				}
  
  				//Set up the lastSelectedImage
  				if (isEditableImage(e.element)) {
  					lastSelectedImage = e.element;
  				}
  			});
  		}
  
  		function isEditableImage(img) {
  			var selectorMatched = editor.dom.is(img, 'img:not([data-mce-object],[data-mce-placeholder])');
  
  			return selectorMatched && (isLocalImage(img) || isCorsImage(img) || editor.settings.imagetools_proxy);
  		}
  
  		function addToolbars() {
  			var toolbarItems = editor.settings.imagetools_toolbar;
  
  			if (!toolbarItems) {
  				toolbarItems = 'rotateleft rotateright | flipv fliph | crop editimage imageoptions';
  			}
  
  			editor.addContextToolbar(
  				isEditableImage,
  				toolbarItems
  			);
  		}
  
  		addButtons();
  		addToolbars();
  		addEvents();
  
  		editor.addCommand('mceEditImage', editImageDialog);
  	};
  
  	PluginManager.add('imagetools', plugin);
  
  	return function() {};
  });
  