/**

 * 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();

				targetPanel.focus();

			};

		}



		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);

		});



		imagePanel.on('crop', crop);

	}



	function edit(blob) {

		return new Promise(function(resolve, reject) {

			open(createState(blob), resolve, reject);

		});

	}



	//edit('img/dogleft.jpg');



	return {

		edit: edit

	};

});

