// Author: Stanisław Wasiutyński
// Date: 14.07.2010
// Depends on RulerDialog. (ruler.js)

(function($) {
	$.fn.big_preview = function(options) {
		var defaults = {
			on_wait: _("Please wait..."),
			show_all: true,
			show_all_label: _("Click to fit image to screen"),
			show_bleeds: _("Show bleeds"),
			show_as_spread: _("Show as spread"),
			one_one_scale: _("Show in scale 1:1"),
			show_thumbnail: _("Show/hides thumbnail display. The thumbnail is visible only when page size exceeds viewport."),
			thumb_move_label: _("Drag to change image position"),
			loading: "../layout/images/progress/big_black.gif"
		};
		options = $.extend(defaults, options);

		var COOKIE_SHOW_BLEEDS 		= 'preview-show-bleeds';
		var COOKIE_SHOW_SPREAD 		= 'preview-show-spread';
		var COOKIE_SHOW_THUMBNAIL = 'preview-show-thumbnails';

		function Preview(container, opts) {
			var self = this;
			this.options = $.extend(defaults, opts);
			this.scale = 1.0;
			this.container = $(container);
			this.controls_container = opts.controls_container ? $(opts.controls_container) : undefined;
			this.show = {
				bleeds: this.getCookie(COOKIE_SHOW_BLEEDS) != 'off', // default on
				spread: this.getCookie(COOKIE_SHOW_SPREAD) == 'on' && this.options.left && this.options.right,  // default off
				thumbnail: this.getCookie(COOKIE_SHOW_THUMBNAIL) == 'on' // default off
			};
			this.ruler = new RulerDialog();
			$j(this.ruler).bind('scale.changed', function() {
				self.onScaleOneToOne();
			});
		}

		Preview.prototype = {
			setCookie: function(name, value) {
				$.cookie(name, value, { path: '/', expires: 40000 });
				return value;
			},
			getCookie: function(name) {
				return $j.cookie(name, undefined, { path: '/' });
			},
			showLoadingMessage: function() {
				var load_img = new Image();
				load_img.src = this.options.loading;
				this.loading = $("<div class='loading ui-corner-all' />").append(load_img).append($("<p />").text(this.options.on_wait));
				this.container.append(this.loading);
			},

			draw: function() {
				this.showLoadingMessage();
				this.drawControls();
				this.drawPages();
			},

			redraw: function() {
				this.redrawControls();
				this.redrawPages();
			},

			drawControls: function() {
				this.draggable = $("<div class='draggable' />");

				this.zoom_val = $("<div class='zoom_val' />");

				//this.zoom_out = $("<a class='slider_button ui-state-default ui-corner-all ui-widget-content' />").text("-");
				this.zoom_out = $(icon_link_tag('', '', 'minus', {className: 'slider_button'}));
				//this.zoom_in = $("<a class='slider_button ui-state-default ui-corner-all ui-widget-content' />").text("+");
				this.zoom_in = $(icon_link_tag('', '', 'plus', {className: 'slider_button'}));
				this.show_bleeds_button = $("<a class='option_button show_bleeds' />")
						.attr('title', this.options.show_bleeds)
						.addClass(this.show.bleeds ? 'on' : 'off')
						.click($.proxy(this.onToggleBleeds, this));
				this.show_spread_button = $("<a class='option_button show_spread' />")
						.attr('title', this.options.show_as_spread)
						.addClass(this.show.spread ? 'on' : 'off')
						.click($.proxy(this.onToggleSpread, this));
				this.one_one_button = $("<a class='option_button one_one' />")
						.attr('title', this.options.one_one_scale)
						.click($.proxy(this.onScaleOneToOne, this))
						.dblclick($.proxy(this.onRulerScale, this));
				this.show_thumbnail_button = $("<a class='option_button show_thumbnail' />")
						.attr('title', this.options.show_thumbnail)
						.addClass(this.show.thumbnail ? 'on' : 'off')
						.click($.proxy(this.onToggleThumbnail, this))

				var self = this;
				this.slider = $("<div class='slider' />").slider({
					value: 1,
					step: 0.05,
					min: 0.1,
					max: 10,
					slide: function(event, ui) {
						self.triggerZoom(ui.value);
					}
				});
				var slider_wrapper = $("<span class='slider_wrapper' />").append(this.slider);

				this.slider_container = $("<div class='slider_container' />")
						.append(this.zoom_out)
						.append(slider_wrapper)
						.append(this.zoom_in);

				if (this.options.bleeds ||
						this.options.left && this.options.left.bleeds ||
						this.options.right && this.options.right.bleeds) {
					this.slider_container.append(this.show_bleeds_button);
				}
				if (this.options.left && this.options.right) {
					this.slider_container.append(this.show_spread_button);
				}
				var display_one_one_button = false;
				if (this.options.left && this.options.right) {
					if(this.options.left.page_width && this.options.right.page_width) display_one_one_button = true;
				}else{
					if(this.options.page_width) display_one_one_button = true;
				}
				if(display_one_one_button){
					this.slider_container.append(this.one_one_button);
				}
				this.slider_container.append(this.show_thumbnail_button);
				this.slider_container.append(this.zoom_val);
				this.in_view = $("<div class='in_view' />").attr("title", options.thumb_move_label);
				this.preview = $("<div class='preview_thumbnail resizable_image_box' />").append(this.in_view).hide();
				this.preview.bind("image_resized", $.proxy(this.resizePreview, this));
				this.left_thumbnail = $("<div class='page_thumbnail left'>");
				this.right_thumbnail = $("<div class='page_thumbnail right'>");
				this.preview.append(this.left_thumbnail).append(this.right_thumbnail);

				this.view_box = $("<div class='view_box' />");
				this.left_page_box = $("<div class='page_box left' />");
				this.right_page_box = $("<div class='page_box right' />");
				this.view_box.append(this.left_page_box).append(this.right_page_box)

				var controls_container = this.controls_container || this.draggable;
				controls_container.append(this.slider_container);
				this.draggable.append(this.preview).append(this.view_box);
				this.draggable.hide();

				this.container.append(this.draggable);
			},

			redrawControls: function() {

			},

			drawPages: function() {
				if (this.options.left && this.options.right) {
					this.pages = [
						new PagePreview(this, this.left_page_box, this.left_thumbnail, this.options.left),
						new PagePreview(this, this.right_page_box, this.right_thumbnail, this.options.right)
					];
					this.pages[0].draw();
					this.pages[1].draw();
				} else {
					this.pages = [ new PagePreview(this, this.left_page_box, this.left_thumbnail, this.options) ];
					this.pages[0].draw();
				}
				this.togglePageBoxes();
			},

			togglePageBoxes: function() {
				this.left_page_box.toggle(this.show.spread || !this.options.left || this.options.left.selected);
				this.right_page_box.toggle(this.show.spread || (this.options.right && this.options.right.selected));
			},

			redrawPages: function() {
				this.togglePageBoxes();
				this.resizeViewBox();
				this.triggerImageResized();
			},

			onPagesLoaded: function() {
				this.draggable.bind('zoom', $.proxy(this.onZoom, this));
				this.draggable.bind('mousewheel', $.proxy(this.onMouseWheel, this));
				this.view_box.bind("fit", $.proxy(this.fitPages, this));
				this.view_box.dblclick(function(e) {
					var xScreen = e.pageX - this.draggable.offset().left;
					var yScreen = e.pageY - this.draggable.offset().top;

					this.triggerZoom(this.scale * 1.5, xScreen, yScreen);
				});
				this.view_box.draggable({drag: $.proxy(this.triggerImageResized, this)});

				this.original_width = this.pages[0].width;
				this.original_height = this.pages[0].height;

				this.in_view.draggable({drag: $.proxy(this.onInviewDrag, this)});

				this.zoom_in.click($.proxy(this.onZoomIn, this));
				this.zoom_in.dblclick(function() { return false; });

				this.zoom_out.click($.proxy(this.onZoomOut, this));
				this.zoom_out.dblclick(function() { return false; });

				this.preview.click($.proxy(this.triggerFitPages, this));

				this.loading.hide();
				this.draggable.show();

				this.slider_container.hide().fadeIn("fast");

				this.triggerFitPages();

				// IE version of user-select:none
				$('.slider_container > a').each(function() {
					this.onselectstart = function() {
						return false
					}
				});
				// Opera version of user-select:none
				$('.slider_container > a').bind('mousedown.disableTextSelect', function() {
					return false;
				});
			},

			triggerImageResized: function() {
				$('.resizable_image_box').trigger("image_resized");
			},

			triggerZoom: function(new_scale, xScreen, yScreen) {
				if (xScreen === undefined) {
					xScreen = this.draggable.width() / 2;
				}
				if (yScreen === undefined) {
					yScreen = this.draggable.height() / 2;
				}
				this.draggable.trigger("zoom", [new_scale, xScreen, yScreen])
			},

			triggerFitPages: function() {
				this.view_box.trigger("fit");
			},

			triggerPageLoaded: function() {
				this.onPagesLoaded();
			},

			onZoom: function(_, new_scale, xScreen, yScreen) {
				var original_scale = this.scale;
				new_scale = new_scale < 0.1 ? 0.1 : (new_scale > 10 ? 10 : new_scale);
				this.scale = new_scale;

				this.repositionViewBox(original_scale, xScreen, yScreen);
				this.resizeViewBox();
				this.triggerImageResized();

				this.slider.slider("value", this.scale);
				if (this.scale !== NaN) {
					this.zoom_val.text(Math.round(this.scale * 100) + "%");
				}
			},

			repositionViewBox: function(original_scale, xScreen, yScreen) {
				var x = parseInt(this.view_box.css('left')) || 0;
				var y = parseInt(this.view_box.css('top')) || 0;

				var xImg = (-x + xScreen) / original_scale;
				var yImg = (-y + yScreen) / original_scale;

				var dx = xImg - (-x + xScreen) / this.scale;
				var dy = yImg - (-y + yScreen) / this.scale;

				this.view_box.css({
					left: Math.round(x - dx * this.scale) + "px",
					top: Math.round(y - dy * this.scale) + "px"
				});
			},

			resizeViewBox: function() {
				var view_size = {};

				if (this.show.spread) {
					var left_bleeds = this.pages[0].bleedMargins();
					var right_bleeds = this.pages[1].bleedMargins();
					var left_size = this.pages[0].scaledImageSize();
					var right_size = this.pages[1].scaledImageSize();
					var view_height = Math.max(left_size.height, right_size.height);

					left_size.width -= left_bleeds.right;
					right_size.width -= right_bleeds.left;

					this.left_page_box
							.css({ width: left_size.width + "px",
										 height: view_height + "px" })
							.show();

					this.right_page_box
							.css({ width: right_size.width + "px",
										 height: view_height + "px" })
							.show();

					this.pages[0].image_box.css('margin-right',
							(!this.show.bleeds ? left_bleeds.right : -left_bleeds.right) + "px");
					this.pages[1].image_box.css('margin-left', -right_bleeds.left + "px");

					view_size = {
						width: left_size.width + right_size.width,
						height: view_height
					};
				} else {
					if (!this.options.left || this.options.left.selected) {
						view_size = this.pages[0].scaledImageSize();
						this.left_page_box
								.css({ width: view_size.width + "px",
											 height: view_size.height + "px" })
								.show();
						this.right_page_box.hide();
					} else {
						view_size = this.pages[1].scaledImageSize();
						this.right_page_box
								.css({ width: view_size.width + "px",
											 height: view_size.height + "px" })
								.show();
						this.left_page_box.hide();
					}
					if (this.pages[0] && this.pages[0].image_box) {
						this.pages[0].image_box.css('margin-right', "0px");
					}
					if (this.pages[1] && this.pages[1].image_box) {
						this.pages[1].image_box.css('margin-left', "0px");
					}
				}

				this.view_box.css({
					width: view_size.width + "px",
					height: view_size.height + "px"
				});
				// Show the thumbnail only if it does not fit inside the view and display is enabled.
				if (this.show.thumbnail && ((this.container.height() * 1.01) <view_size.height || (this.container.width() * 1.01) < view_size.width )) {
					this.preview.fadeIn("fast");
				} else {
					this.preview.fadeOut("fast");
				}
			},

			onZoomIn: function() {
				this.triggerZoom(this.scale * 1.5);
				return false;
			},

			onZoomOut: function() {
				this.triggerZoom(this.scale / 1.5);
				return false;
			},

			onMouseWheel: function(e, delta) {
				var xScreen = e.pageX - this.draggable.offset().left;
				var yScreen = e.pageY - this.draggable.offset().top;

				// determine the new scale
				if (delta > 0) d = 12 / 10;
				else d = 10 / 12;

				this.triggerZoom(this.scale * d, xScreen, yScreen);
				return false;
			},

			onInviewDrag: function(event) {
				var y_ratio = this.pages[0].trimSize().height / this.preview.height();
				var x = parseInt(this.in_view.css('left'));
				var y = parseInt(this.in_view.css('top'));

				this.view_box.css({
					left: Math.round(-x * y_ratio) + "px",
					top: Math.round(-y * y_ratio) + "px"
				});
			},
			onToggleBleeds: function() {
				this.show_bleeds_button.removeClass(this.show.bleeds ? 'on' : 'off');
				this.show.bleeds = !this.show.bleeds;
				this.show_bleeds_button.addClass(this.show.bleeds ? 'on' : 'off');
				this.setCookie(COOKIE_SHOW_BLEEDS, this.show.bleeds ? 'on' : 'off');
				this.redraw();
			},
			onToggleSpread: function() {
				this.show_spread_button.removeClass(this.show.spread ? 'on' : 'off');
				this.show.spread = !this.show.spread;
				this.show_spread_button.addClass(this.show.spread ? 'on' : 'off');
				this.setCookie(COOKIE_SHOW_SPREAD, this.show.spread ? 'on' : 'off');
				this.redraw();
				this.fitPages();
			},
			onScaleOneToOne: function() {
				var pt2px_scale = this.ruler.getScale();
				var pt_width = Units.mm2pt(this.pages[0].options.page_width);
				var px_width = this.pages[0].width;
				var scale = pt_width * pt2px_scale / px_width;
				this.triggerZoom(scale);
			},
			onRulerScale: function() {
					this.ruler.open();
			},
			onToggleThumbnail: function() {
				this.show_thumbnail_button.removeClass(this.show.thumbnail ? 'on' : 'off');
				this.show.thumbnail = !this.show.thumbnail;
				this.show_thumbnail_button.addClass(this.show.thumbnail ? 'on' : 'off');
				this.setCookie(COOKIE_SHOW_THUMBNAIL, this.show.thumbnail ? 'on' : 'off');
				this.redraw();
				/*
				if (this.show.thumbnail) {
					$(this.preview).fadeIn('fast');
				} else {
					$(this.preview).fadeOut('fast');
				} */
			},
			resizePreview: function() {
				var preview_size = {};
				var width_proportions = 1;
				var max_preview_size = {
					height: Math.round(this.container.height() *0.3),
					width: Math.round(this.container.width() *0.25)
				};

				if (this.show.spread) {
					preview_size.width = this.pages[0].thumbnail.naturalWidth + this.pages[1].thumbnail.naturalWidth;
					preview_size.height = Math.max(this.pages[0].thumbnail.naturalHeight, this.pages[1].thumbnail.naturalHeight);
					width_proportions = this.pages[0].thumbnail.naturalWidth/(this.pages[0].thumbnail.naturalWidth+this.pages[1].thumbnail.naturalWidth);
				} else if (!this.options.left || this.options.left.selected) {
					preview_size.width = this.pages[0].thumbnail.naturalWidth;
					preview_size.height = this.pages[0].thumbnail.naturalHeight;
				} else {
					preview_size.width = this.pages[1].thumbnail.naturalWidth;
					preview_size.height = this.pages[1].thumbnail.naturalHeight;
					width_proportions = -1;
				}


				this.fitThumbnails(preview_size, max_preview_size);
				this.setThumbnailsSize(preview_size, width_proportions);

				this.preview.css({
					width: preview_size.width + "px",
					height: preview_size.height + "px"
				});
				var image = {
					width: this.view_box.width(),
					height: this.view_box.height()
				};

				var ratio = preview_size.width / image.width;
				var w = parseInt(preview_size.width / (image.width / this.draggable.width()));
				var h = parseInt(preview_size.height / (image.height / this.draggable.height()));
				if (!isNaN(w) && !isNaN(h)) {
					var x = -ratio * parseInt(this.view_box.css('left'));
					var y = -ratio * parseInt(this.view_box.css('top'));

					this.in_view.css({
						width: w + "px",
						height: h + "px",
						left: x + "px",
						top: y + "px"
					})
				}
			},

			fitPages: function() {
				var view_height = this.show.spread ? Math.max(this.pages[0].height, this.pages[1].height) : this.pages[0].height;
				var view_width = this.show.spread ? this.pages[0].width + this.pages[1].width : this.pages[0].width;
				view_width -= (this.pages[0].bleedMargins(this.pages[0]).right || 0.0);
				view_width -= (this.show.spread ? this.pages[1].bleedMargins(this.pages[1]).left || 0.0 : 0.0);
				var vertical_scale = this.container.height() / view_height;
				var horizontal_scale = this.container.width() / view_width;
				this.triggerZoom(Math.min(vertical_scale, horizontal_scale), 0, 0);

				// Move to the middle
				this.view_box.css({
					left: Math.max(Math.round((this.draggable.width() - this.view_box.width()) / 2), 0) + "px",
					top: Math.max(Math.round((this.draggable.height() - this.view_box.height()) / 2), 0) + "px"
				});

				this.triggerImageResized();
			},

			fitThumbnails: function(preview_size, max_preview_size){
				var original_proportions = preview_size.width/preview_size.height;
				if ((preview_size.height-max_preview_size.height)/max_preview_size.height > (preview_size.width-max_preview_size.width)/max_preview_size.width){
					if (preview_size.height > max_preview_size.height) preview_size.height = max_preview_size.height;
					preview_size.width = Math.round(preview_size.height * original_proportions);
				}else{
					if (preview_size.width > max_preview_size.width) preview_size.width = max_preview_size.width;
					preview_size.height = Math.round(preview_size.width/(original_proportions));
				}
			},

			setThumbnailsSize: function(preview_size, width_proportions){
				var left_thumbnail_width = width_proportions == -1 ? 0 : Math.round(preview_size.width*width_proportions);
				var left_css = {
					height : preview_size.height,
					width: left_thumbnail_width
				};
				var right_css = {
					height : preview_size.height,
					width: preview_size.width-left_thumbnail_width
				};
				this.preview.find('.page_thumbnail.left').css(left_css).find('img').css(left_css);
				this.preview.find('.page_thumbnail.right').css(right_css).find('img').css(right_css);
			}

		};

		function PagePreview(view, container, preview_container, options) {
			this.view = view;
			this.container = container;
			this.preview_container = preview_container;
			this.show = view.show;
			this.options = options;
			this.image_url = options.image_url;
			this.thumbnail_url = options.thumbnail_url;
			this.page_no = options.page_no;
			this.selected = options.selected;
		}

		PagePreview.prototype = {
			draw: function() {
				this.image_box = $("<div class='image_box' />");
				if (this.options.bleeds) {
					this.trim_box = $("<div class='trim_box' />");
					this.image_box.append(this.trim_box);
					this.trim_box.hide();
				}
				this.container.append(this.image_box);

				this.thumbnail = new Image();
				$(this.thumbnail).load($.proxy(this.previewImageLoaded, this));
				this.thumbnail.src = this.thumbnail_url;

				this.image = new Image();
				$(this.image).load($.proxy(this.imageLoaded, this))
						.attr('src', this.image_url || Routes.common_image_path('page_tiles/page_empty.png'))
						.addClass('resizable_image_box');
				this.image.onerror = function() { alert("Image file " + this.image_url + " could not be loaded!"); };
			},

			redraw: function() {
				this.resizeImage();
			},

			previewImageLoaded: function() {
				$(this.thumbnail).attr("title", this.options.show_all_label);
				this.preview_container.prepend(this.thumbnail);
				this.preview_container.css({
					width: this.thumbnail.width,
					height: this.thumbnail.height
				});
				this.view.triggerImageResized();

				if (this.thumbnail && this.view.show.thumbnail) {
					//this.view.preview.fadeIn('fast');
				}
			},

			imageLoaded: function() {
				this.width = this.image.width;
				this.height = this.image.height;

				this.image_box.append(this.image).css({
					width: this.width + "px",
					height: this.height + "px"
				});
				var self = this;

				$(this.image).bind("image_resized", $.proxy(this.resizeImage, this));
				this.image_box.dblclick($.proxy(this.onPageClicked, this))

				this.view.triggerPageLoaded();
			},

			// returns bleeds in current scale or relative to the given image size
			bleedMargins: function(image_size) {
				var trim = this.trimSize(image_size);
				var page = { width: this.options.page_width, height: this.options.page_height };
				if( image_size===undefined ) {
					image_size = { width: this.image.width, height: this.image.height };
				}
				var bleeds = this.options.bleeds;
				if( bleeds ) {
					var left = Math.round(bleeds.left * image_size.width / page.width);
					var right = image_size.width - trim.width - left;
					var top = Math.round(bleeds.top * image_size.height / page.height);
					var bottom = image_size.height - trim.height - top;
					return { left: left, right: right, top: top, bottom: bottom };
				} else {
					return { left: 0, right: 0, top: 0, bottom: 0 };
				}
			},

			// returns trim size in current scale or relative to the given image size
			trimSize: function(image_size) {
				if( image_size===undefined ) {
					image_size = { width: this.image.width, height: this.image.height };
				}
				if (this.options.bleeds) {
					var trim = {};
					var page = { width: this.options.page_width, height: this.options.page_height };
					var bleeds = this.options.bleeds;
					// Do not extend trim box on precision errors - make a floor
					trim.width = Math.floor((page.width - bleeds.left - bleeds.right) * image_size.width / page.width);
					trim.height = Math.floor((page.height - bleeds.top - bleeds.bottom) * image_size.height / page.height);
					return trim;
				} else {
					return image_size;
				}
			},

			scaledImageSize: function() {
				return {
					width: Math.round(this.width * this.view.scale),
					height: Math.round(this.height * this.view.scale)
				};
			},

			resizeImage: function() {
				var scaled_size = this.scaledImageSize();
				this.image.width = scaled_size.width;
				this.image.height = scaled_size.height;
				if (this.trim_box) {
					if (this.show.bleeds) {
						this.cropToBleedBox();
						this.resizeTrimBox();
						this.trim_box.show();
					} else {
						this.cropToTrimBox();
						this.trim_box.hide();
					}
				} else {
					this.cropToBleedBox();
				}
			},

			resizeTrimBox: function() {
				var bleeds = this.bleedMargins();
				this.trim_box.css({
					width: this.image.width - bleeds.left - bleeds.right + "px", // a real border size is +2px
					height: this.image.height - bleeds.top - bleeds.bottom + "px",
					left: bleeds.left - 1 + "px", // -1px because of border
					top: bleeds.top - 1 + "px"
				});
			},

			cropToBleedBox: function() {
				this.image_box.css({
					width: this.image.width + "px",
					height: this.image.height + "px",
					left: 0,
					top: 0
				});
				$(this.image).css('margin', 0);
			},

			cropToTrimBox: function() {
				var bleeds = this.bleedMargins();
				this.image_box.css({
					width: this.image.width - bleeds.left - bleeds.right + "px",
					height: this.image.height - bleeds.top - bleeds.bottom + "px",
					left: bleeds.left + "px",
					top: bleeds.top + "px"
				});
				$(this.image).css({
					'margin-left': -bleeds.left + "px",
					'margin-top': -bleeds.top + "px"
				});
			},

			onPageClicked: function() {
				this.view.container.trigger("page-select", {page_no: this.page_no});
			}
		};

		return this.each(function() {
			var preview = new Preview(this, options);
			preview.draw();
		});

	};
})(jQuery);

