/**
 * ImagePanel.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
 */

/**
 * ...
 *
 * @-x-less ImagePanel.less
 */
define("tinymce/imagetoolsplugin/ImagePanel", [
	"global!tinymce.ui.Control",
	"global!tinymce.ui.DragHelper",
	"global!tinymce.geom.Rect",
	"global!tinymce.util.Tools",
	"global!tinymce.util.Promise",
	"tinymce/imagetoolsplugin/CropRect"
], function(Control, DragHelper, Rect, Tools, Promise, CropRect) {
	function loadImage(image) {
		return new Promise(function(resolve) {
			function loaded() {
				image.removeEventListener('load', loaded);
				resolve(image);
			}

			if (image.complete) {
				resolve(image);
			} else {
				image.addEventListener('load', loaded);
			}
		});
	}

	return Control.extend({
		Defaults: {
			classes: "imagepanel"
		},

		selection: function(rect) {
			if (arguments.length) {
				this.state.set('rect', rect);
				return this;
			}

			return this.state.get('rect');
		},

		imageSize: function() {
			var viewRect = this.state.get('viewRect');

			return {
				w: viewRect.w,
				h: viewRect.h
			};
		},

		toggleCropRect: function(state) {
			this.state.set('cropEnabled', state);
		},

		imageSrc: function(url) {
			var self = this, img = new Image();

			img.src = url;

			loadImage(img).then(function() {
				var rect, $img, lastRect = self.state.get('viewRect');

				$img = self.$el.find('img');
				if ($img[0]) {
					$img.replaceWith(img);
				} else {
					self.getEl().appendChild(img);
				}

				rect = {x: 0, y: 0, w: img.naturalWidth, h: img.naturalHeight};
				self.state.set('viewRect', rect);
				self.state.set('rect', Rect.inflate(rect, -20, -20));

				if (!lastRect || lastRect.w != rect.w || lastRect.h != rect.h) {
					self.zoomFit();
				}

				self.repaintImage();
				self.fire('load');
			});
		},

		zoom: function(value) {
			if (arguments.length) {
				this.state.set('zoom', value);
				return this;
			}

			return this.state.get('zoom');
		},

		postRender: function() {
			this.imageSrc(this.settings.imageSrc);
			return this._super();
		},

		zoomFit: function() {
			var self = this, $img, pw, ph, w, h, zoom, padding;

			padding = 10;
			$img = self.$el.find('img');
			pw = self.getEl().clientWidth;
			ph = self.getEl().clientHeight;
			w = $img[0].naturalWidth;
			h = $img[0].naturalHeight;
			zoom = Math.min((pw - padding) / w, (ph - padding) / h);

			if (zoom >= 1) {
				zoom = 1;
			}

			self.zoom(zoom);
		},

		repaintImage: function() {
			var x, y, w, h, pw, ph, $img, zoom, rect, elm;

			elm = this.getEl();
			zoom = this.zoom();
			rect = this.state.get('rect');
			$img = this.$el.find('img');
			pw = elm.offsetWidth;
			ph = elm.offsetHeight;
			w = $img[0].naturalWidth * zoom;
			h = $img[0].naturalHeight * zoom;
			x = Math.max(0, pw / 2 - w / 2);
			y = Math.max(0, ph / 2 - h / 2);

			$img.css({
				left: x,
				top: y,
				width: w,
				height: h
			});

			if (this.cropRect) {
				this.cropRect.setRect({
					x: rect.x * zoom + x,
					y: rect.y * zoom + y,
					w: rect.w * zoom,
					h: rect.h * zoom
				});

				this.cropRect.setClampRect({
					x: x,
					y: y,
					w: w,
					h: h
				});

				this.cropRect.setViewPortRect({
					x: 0,
					y: 0,
					w: pw,
					h: ph
				});
			}
		},

		bindStates: function() {
			var self = this;

			function setupCropRect(rect) {
				self.cropRect = new CropRect(
					rect,
					self.state.get('viewRect'),
					self.state.get('viewRect'),
					self.getEl(),
					function() {
						self.fire('crop');
					}
				);

				self.cropRect.on('updateRect', function(e) {
					var rect = e.rect, zoom = self.zoom();

					rect = {
						x: Math.round(rect.x / zoom),
						y: Math.round(rect.y / zoom),
						w: Math.round(rect.w / zoom),
						h: Math.round(rect.h / zoom)
					};

					self.state.set('rect', rect);
				});

				self.on('remove', self.cropRect.destroy);
			}

			self.state.on('change:cropEnabled', function(e) {
				self.cropRect.toggleVisibility(e.value);
				self.repaintImage();
			});

			self.state.on('change:zoom', function() {
				self.repaintImage();
			});

			self.state.on('change:rect', function(e) {
				var rect = e.value;

				if (!self.cropRect) {
					setupCropRect(rect);
				}

				self.cropRect.setRect(rect);
			});
		}
	});
});
