text: /**
   * Dialog.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
   */
  
  /**
   * ...
   */
  define("tinymce/imagetoolsplugin/Dialog", [
  	"global!tinymce.dom.DOMUtils",
  	"global!tinymce.util.Tools",
  	"global!tinymce.util.Promise",
  	"global!tinymce.ui.Factory",
  	"global!tinymce.ui.Form",
  	"global!tinymce.ui.Container",
  	"tinymce/imagetoolsplugin/ImagePanel",
  	"ephox/imagetools/api/ImageTransformations",
  	"ephox/imagetools/api/BlobConversions",
  	"tinymce/imagetoolsplugin/UndoStack"
  ], function(DOMUtils, Tools, Promise, Factory, Form, Container, ImagePanel, ImageTransformations, BlobConversions, UndoStack) {
  	function createState(blob) {
  		return {
  			blob: blob,
  			url: URL.createObjectURL(blob)
  		};
  	}
  
  	function destroyState(state) {
  		if (state) {
  			URL.revokeObjectURL(state.url);
  		}
  	}
  
  	function destroyStates(states) {
  		Tools.each(states, destroyState);
  	}
  
  	function open(currentState, resolve, reject) {
  		var win, undoStack = new UndoStack(), mainPanel, filtersPanel, tempState,
  			cropPanel, resizePanel, flipRotatePanel, imagePanel, sidePanel, mainViewContainer,
  			invertPanel, brightnessPanel, huePanel, saturatePanel, contrastPanel, grayscalePanel,
  			sepiaPanel, colorizePanel, sharpenPanel, embossPanel, gammaPanel, exposurePanel, panels,
  			width, height, ratioW, ratioH;
  
  		function recalcSize(e) {
  			var widthCtrl, heightCtrl, newWidth, newHeight;
  
  			widthCtrl = win.find('#w')[0];
  			heightCtrl = win.find('#h')[0];
  
  			newWidth = parseInt(widthCtrl.value(), 10);
  			newHeight = parseInt(heightCtrl.value(), 10);
  
  			if (win.find('#constrain')[0].checked() && width && height && newWidth && newHeight) {
  				if (e.control.settings.name == 'w') {
  					newHeight = Math.round(newWidth * ratioW);
  					heightCtrl.value(newHeight);
  				} else {
  					newWidth = Math.round(newHeight * ratioH);
  					widthCtrl.value(newWidth);
  				}
  			}
  
  			width = newWidth;
  			height = newHeight;
  		}
  
  		function floatToPercent(value) {
  			return Math.round(value * 100) + '%';
  		}
  
  		function updateButtonUndoStates() {
  			win.find('#undo').disabled(!undoStack.canUndo());
  			win.find('#redo').disabled(!undoStack.canRedo());
  			win.statusbar.find('#save').disabled(!undoStack.canUndo());
  		}
  
  		function disableUndoRedo() {
  			win.find('#undo').disabled(true);
  			win.find('#redo').disabled(true);
  		}
  
  		function displayState(state) {
  			if (state) {
  				imagePanel.imageSrc(state.url);
  			}
  		}
  
  		function switchPanel(targetPanel) {
  			return function() {
  				var hidePanels = Tools.grep(panels, function(panel) {
  					return panel.settings.name != targetPanel;
  				});
  
  				Tools.each(hidePanels, function(panel) {
  					panel.hide();
  				});
  
  				targetPanel.show();
  			};
  		}
  
  		function addTempState(blob) {
  			tempState = createState(blob);
  			displayState(tempState);
  		}
  
  		function addBlobState(blob) {
  			currentState = createState(blob);
  			displayState(currentState);
  			destroyStates(undoStack.add(currentState).removed);
  			updateButtonUndoStates();
  		}
  
  		function crop() {
  			var rect = imagePanel.selection();
  
  			ImageTransformations.crop(currentState.blob, rect.x, rect.y, rect.w, rect.h).then(function(blob) {
  				addBlobState(blob);
  				cancel();
  			});
  		}
  
  		function tempAction(fn) {
  			var args = [].slice.call(arguments, 1);
  
  			return function() {
  				var state = tempState || currentState;
  
  				fn.apply(this, [state.blob].concat(args)).then(addTempState);
  			};
  		}
  
  		function action(fn) {
  			var args = [].slice.call(arguments, 1);
  
  			return function() {
  				fn.apply(this, [currentState.blob].concat(args)).then(addBlobState);
  			};
  		}
  
  		function cancel() {
  			displayState(currentState);
  			destroyState(tempState);
  			switchPanel(mainPanel)();
  			updateButtonUndoStates();
  		}
  
  		function applyTempState() {
  			if (tempState) {
  				addBlobState(tempState.blob);
  				cancel();
  			}
  		}
  
  		function zoomIn() {
  			var zoom = imagePanel.zoom();
  
  			if (zoom < 2) {
  				zoom += 0.1;
  			}
  
  			imagePanel.zoom(zoom);
  		}
  
  		function zoomOut() {
  			var zoom = imagePanel.zoom();
  
  			if (zoom > 0.1) {
  				zoom -= 0.1;
  			}
  
  			imagePanel.zoom(zoom);
  		}
  
  		function undo() {
  			currentState = undoStack.undo();
  			displayState(currentState);
  			updateButtonUndoStates();
  		}
  
  		function redo() {
  			currentState = undoStack.redo();
  			displayState(currentState);
  			updateButtonUndoStates();
  		}
  
  		function save() {
  			resolve(currentState.blob);
  			win.close();
  		}
  
  		function createPanel(items) {
  			return new Form({
  				layout: 'flex',
  				direction: 'row',
  				labelGap: 5,
  				border: '0 0 1 0',
  				align: 'center',
  				pack: 'center',
  				padding: '0 10 0 10',
  				spacing: 5,
  				flex: 0,
  				minHeight: 60,
  				defaults: {
  					classes: 'imagetool',
  					type: 'button'
  				},
  				items: items
  			});
  		}
  
  		function createFilterPanel(title, filter) {
  			return createPanel([
  				{text: 'Back', onclick: cancel},
  				{type: 'spacer', flex: 1},
  				{text: 'Apply', subtype: 'primary', onclick: applyTempState}
  			]).hide().on('show', function() {
  				disableUndoRedo();
  
  				filter(currentState.blob).then(function(blob) {
  					var newTempState = createState(blob);
  
  					displayState(newTempState);
  					destroyState(tempState);
  					tempState = newTempState;
  				});
  			});
  		}
  
  		function createVariableFilterPanel(title, filter, value, min, max) {
  			function update(value) {
  				filter(currentState.blob, value).then(function(blob) {
  					var newTempState = createState(blob);
  					displayState(newTempState);
  					destroyState(tempState);
  					tempState = newTempState;
  				});
  			}
  
  			return createPanel([
  				{text: 'Back', onclick: cancel},
  				{type: 'spacer', flex: 1},
  				{
  					type: 'slider',
  					flex: 1,
  					ondragend: function(e) {
  						update(e.value);
  					},
  					minValue: min,
  					maxValue: max,
  					value: value,
  					previewFilter: floatToPercent
  				},
  				{type: 'spacer', flex: 1},
  				{text: 'Apply', subtype: 'primary', onclick: applyTempState}
  			]).hide().on('show', function() {
  				this.find('slider').value(value);
  				disableUndoRedo();
  			});
  		}
  
  		function createRgbFilterPanel(title, filter) {
  			function update() {
  				var r, g, b;
  
  				r = win.find('#r')[0].value();
  				g = win.find('#g')[0].value();
  				b = win.find('#b')[0].value();
  
  				filter(currentState.blob, r, g, b).then(function(blob) {
  					var newTempState = createState(blob);
  					displayState(newTempState);
  					destroyState(tempState);
  					tempState = newTempState;
  				});
  			}
  
  			return createPanel([
  				{text: 'Back', onclick: cancel},
  				{type: 'spacer', flex: 1},
  				{
  					type: 'slider', label: 'R', name: 'r', minValue: 0,
  					value: 1, maxValue: 2, ondragend: update, previewFilter: floatToPercent
  				},
  				{
  					type: 'slider', label: 'G', name: 'g', minValue: 0,
  					value: 1, maxValue: 2, ondragend: update, previewFilter: floatToPercent
  				},
  				{
  					type: 'slider', label: 'B', name: 'b', minValue: 0,
  					value: 1, maxValue: 2, ondragend: update, previewFilter: floatToPercent
  				},
  				{type: 'spacer', flex: 1},
  				{text: 'Apply', subtype: 'primary', onclick: applyTempState}
  			]).hide().on('show', function() {
  				win.find('#r,#g,#b').value(1);
  				disableUndoRedo();
  			});
  		}
  
  		cropPanel = createPanel([
  			{text: 'Back', onclick: cancel},
  			{type: 'spacer', flex: 1},
  			{text: 'Apply', subtype: 'primary', onclick: crop}
  		]).hide().on('show hide', function(e) {
  			imagePanel.toggleCropRect(e.type == 'show');
  		}).on('show', disableUndoRedo);
  
  		function toggleConstrain(e) {
  			if (e.control.value() === true) {
  				ratioW = height / width;
  				ratioH = width / height;
  			}
  		}
  
  		resizePanel = createPanel([
  			{text: 'Back', onclick: cancel},
  			{type: 'spacer', flex: 1},
  			{type: 'textbox', name: 'w', label: 'Width', size: 4, onkeyup: recalcSize},
  			{type: 'textbox', name: 'h', label: 'Height', size: 4, onkeyup: recalcSize},
  			{type: 'checkbox', name: 'constrain', text: 'Constrain proportions', checked: true, onchange: toggleConstrain},
  			{type: 'spacer', flex: 1},
  			{text: 'Apply', subtype: 'primary', onclick: 'submit'}
  		]).hide().on('submit', function(e) {
  			var width = parseInt(win.find('#w').value(), 10),
  				height = parseInt(win.find('#h').value(), 10);
  
  			e.preventDefault();
  
  			action(ImageTransformations.resize, width, height)();
  			cancel();
  		}).on('show', disableUndoRedo);
  
  		flipRotatePanel = createPanel([
  			{text: 'Back', onclick: cancel},
  			{type: 'spacer', flex: 1},
  			{icon: 'fliph', tooltip: 'Flip horizontally', onclick: tempAction(ImageTransformations.flip, 'h')},
  			{icon: 'flipv', tooltip: 'Flip vertically', onclick: tempAction(ImageTransformations.flip, 'v')},
  			{icon: 'rotateleft', tooltip: 'Rotate counterclockwise', onclick: tempAction(ImageTransformations.rotate, -90)},
  			{icon: 'rotateright', tooltip: 'Rotate clockwise', onclick: tempAction(ImageTransformations.rotate, 90)},
  			{type: 'spacer', flex: 1},
  			{text: 'Apply', subtype: 'primary', onclick: applyTempState}
  		]).hide().on('show', disableUndoRedo);
  
  		invertPanel = createFilterPanel("Invert", ImageTransformations.invert);
  		sharpenPanel = createFilterPanel("Sharpen", ImageTransformations.sharpen);
  		embossPanel = createFilterPanel("Emboss", ImageTransformations.emboss);
  
  		brightnessPanel = createVariableFilterPanel("Brightness", ImageTransformations.brightness, 0, -1, 1);
  		huePanel = createVariableFilterPanel("Hue", ImageTransformations.hue, 180, 0, 360);
  		saturatePanel = createVariableFilterPanel("Saturate", ImageTransformations.saturate, 0, -1, 1);
  		contrastPanel = createVariableFilterPanel("Contrast", ImageTransformations.contrast, 0, -1, 1);
  		grayscalePanel = createVariableFilterPanel("Grayscale", ImageTransformations.grayscale, 0, 0, 1);
  		sepiaPanel = createVariableFilterPanel("Sepia", ImageTransformations.sepia, 0, 0, 1);
  		colorizePanel = createRgbFilterPanel("Colorize", ImageTransformations.colorize);
  		gammaPanel = createVariableFilterPanel("Gamma", ImageTransformations.gamma, 0, -1, 1);
  		exposurePanel = createVariableFilterPanel("Exposure", ImageTransformations.exposure, 1, 0, 2);
  
  		filtersPanel = createPanel([
  			{text: 'Back', onclick: cancel},
  			{type: 'spacer', flex: 1},
  			{text: 'hue', icon: 'hue', onclick: switchPanel(huePanel)},
  			{text: 'saturate', icon: 'saturate', onclick: switchPanel(saturatePanel)},
  			{text: 'sepia', icon: 'sepia', onclick: switchPanel(sepiaPanel)},
  			{text: 'emboss', icon: 'emboss', onclick: switchPanel(embossPanel)},
  			{text: 'exposure', icon: 'exposure', onclick: switchPanel(exposurePanel)},
  			{type: 'spacer', flex: 1}
  		]).hide();
  
  		mainPanel = createPanel([
  			{tooltip: 'Crop', icon: 'crop', onclick: switchPanel(cropPanel)},
  			{tooltip: 'Resize', icon: 'resize2', onclick: switchPanel(resizePanel)},
  			{tooltip: 'Orientation', icon: 'orientation', onclick: switchPanel(flipRotatePanel)},
  			{tooltip: 'Brightness', icon: 'sun', onclick: switchPanel(brightnessPanel)},
  			{tooltip: 'Sharpen', icon: 'sharpen', onclick: switchPanel(sharpenPanel)},
  			{tooltip: 'Contrast', icon: 'contrast', onclick: switchPanel(contrastPanel)},
  			{tooltip: 'Color levels', icon: 'drop', onclick: switchPanel(colorizePanel)},
  			{tooltip: 'Gamma', icon: 'gamma', onclick: switchPanel(gammaPanel)},
  			{tooltip: 'Invert', icon: 'invert', onclick: switchPanel(invertPanel)}
  			//{text: 'More', onclick: switchPanel(filtersPanel)}
  		]);
  
  		imagePanel = new ImagePanel({
  			flex: 1,
  			imageSrc: currentState.url
  		});
  
  		sidePanel = new Container({
  			layout: 'flex',
  			direction: 'column',
  			border: '0 1 0 0',
  			padding: 5,
  			spacing: 5,
  			items: [
  				{type: 'button', icon: 'undo', tooltip: 'Undo', name: 'undo', onclick: undo},
  				{type: 'button', icon: 'redo', tooltip: 'Redo', name: 'redo', onclick: redo},
  				{type: 'button', icon: 'zoomin', tooltip: 'Zoom in', onclick: zoomIn},
  				{type: 'button', icon: 'zoomout', tooltip: 'Zoom out', onclick: zoomOut}
  			]
  		});
  
  		mainViewContainer = new Container({
  			type: 'container',
  			layout: 'flex',
  			direction: 'row',
  			align: 'stretch',
  			flex: 1,
  			items: [sidePanel, imagePanel]
  		});
  
  		panels = [
  			mainPanel,
  			cropPanel,
  			resizePanel,
  			flipRotatePanel,
  			filtersPanel,
  			invertPanel,
  			brightnessPanel,
  			huePanel,
  			saturatePanel,
  			contrastPanel,
  			grayscalePanel,
  			sepiaPanel,
  			colorizePanel,
  			sharpenPanel,
  			embossPanel,
  			gammaPanel,
  			exposurePanel
  		];
  
  		win = Factory.create('window', {
  			layout: 'flex',
  			direction: 'column',
  			align: 'stretch',
  			minWidth: Math.min(DOMUtils.DOM.getViewPort().w, 800),
  			minHeight: Math.min(DOMUtils.DOM.getViewPort().h, 650),
  			title: 'Edit image',
  			items: panels.concat([mainViewContainer]),
  			buttons: [
  				{text: 'Save', name: 'save', subtype: 'primary', onclick: save},
  				{text: 'Cancel', onclick: 'close'}
  			]
  		});
  
  		win.renderTo(document.body).reflow();
  
  		win.on('close', function() {
  			reject();
  			destroyStates(undoStack.data);
  			undoStack = null;
  			tempState = null;
  		});
  
  		undoStack.add(currentState);
  		updateButtonUndoStates();
  
  		imagePanel.on('load', function() {
  			width = imagePanel.imageSize().w;
  			height = imagePanel.imageSize().h;
  			ratioW = height / width;
  			ratioH = width / height;
  
  			win.find('#w').value(width);
  			win.find('#h').value(height);
  		});
  	}
  
  	function edit(blob) {
  		return new Promise(function(resolve, reject) {
  			open(createState(blob), resolve, reject);
  		});
  	}
  
  	//edit('img/dogleft.jpg');
  
  	return {
  		edit: edit
  	};
  });
  