lclass("Photo", {
	cons: function(id, thumbUrl, template, copyCount, originalId, originalFileName, originalWidth, originalHeight, quality, dropped) {
		this.id = id;
		this.thumbUrl = thumbUrl;
		this.template = template;
		this.originalId = originalId;
		this.originalFileName = originalFileName;
		this.quality = quality;
		var fn = originalFileName;
		if (fn.length >= 21) {
			fn = fn.substring(0, 20) + "...";
		}
		var el = this.el = new LElementNode("li", {_class: "ImagePickerQuality" + this.quality},
			this.cropDiv = new LElementNode("div", {_class: "ImagePickerCrop"},
				this.elImg = new LElementNode("img", {src: thumbUrl, width: "130"}),
				this.elDropped = new LElementNode("div", {_class: "DroppedIndicator"},
					new LElementNode("div", new LElementNode("span", ImagePicker.LANG["Dropped"]))
				)
			),
			fn
		);
		this.cropDiv.apply({
			width: Math.floor(this.template.listImgSize.w) + "px",
			height: Math.floor(this.template.listImgSize.h) + "px"
		});
		this.el.obj = this;
		
		this.oSize = {w: originalWidth, h: originalHeight};
		this.ratio = this.oSize.w / this.oSize.h;
		this.cropRect = {};
		this.autoCrop(true);

		var makeccel = function(cls) {
			var elcc = new LElementNode("div", {_class: cls});
			el.append(elcc);
			return elcc;
		};

		this.copyCountEls = [];
		this.copyCountEls[0] = makeccel("CopyCountBg0");
		this.copyCountEls[1] = makeccel("CopyCountBg1");
		this.copyCountEls[2] = makeccel("CopyCountBg2");
		this.copyCountEls[3] = makeccel("CopyCountBg3");
		this.copyCountEls[4] = makeccel("CopyCountFg");

		this.setCopyCount(Number(copyCount), true);
		this.setDropped(dropped && dropped.toLowerCase() == "true", true);
		
		this.actualId = (Photo.isCloneId(this.originalId) ? this.id : this.originalId);

		this.updateXmlString();
	},

	destroy: function() {
		this.el.obj = null;
		this.el.removeSelf();
	},

	calculateQuality: function(qualityLevels) {
		var hdpi = (this.cropRect.w * ImagePicker.MM_PER_INCH) / this.template.width;
		var vdpi = (this.cropRect.h * ImagePicker.MM_PER_INCH) / this.template.height;

		this.dpi = Math.min(hdpi, vdpi);

		var i;

		for (i = 0; i < qualityLevels.length; i++) {
			if (this.dpi >= qualityLevels[i]) {
				this.quality = i;
				break;
			}
		}

		this.el.setClass("ImagePickerQuality" + this.quality);
	},

	autoCrop: function(noUpdate) {
		if (this.ratio > this.template.ratio) {
			// Clamp height
			this.cropRect.h = this.oSize.h;
			this.cropRect.y = 0;
			this.cropRect.w = this.cropRect.h * this.template.ratio;
			this.cropRect.x = (this.oSize.w - this.cropRect.w) / 2;
		} else {
			// Clamp width
			this.cropRect.w = this.oSize.w;
			this.cropRect.x = 0;
			this.cropRect.h = this.cropRect.w / this.template.ratio;
			this.cropRect.y = (this.oSize.h - this.cropRect.h) / 2;
		}
		
		this.updateCropElement();

		if (!noUpdate) {
			this.updateXmlString();
		}
	},

	updateCropElement: function() {
		var listIW = Math.floor(this.template.listImgSize.w * (this.oSize.w / this.cropRect.w));
		var listIH = Math.floor(this.template.listImgSize.h * (this.oSize.h / this.cropRect.h));
		var listIX = Math.floor(this.cropRect.x * (0 - (this.template.listImgSize.w / this.cropRect.w)));
		var listIY = Math.floor(this.cropRect.y * (0 - (this.template.listImgSize.h / this.cropRect.h)));

		this.elImg.apply({
			width: listIW + "px",
			height: listIH + "px",
			left: listIX + "px",
			top: listIY + "px"
		});
	},

	setCopyCount: function(copyCount, noUpdate) {
		this.copyCount = copyCount;

		this.setCopyCountElText("x" + copyCount);

		if (!noUpdate) {
			this.updateXmlString();
		}
	},
	
	setCopyCountElText: function(t) {
		var i;

		for (i = 0; i < 5; i++) {
			this.copyCountEls[i].setText(t);
		}
	},

	setDropped: function(dropped, noUpdate) {
		this.dropped = dropped;
		if (this.dropped) {
			this.el.addClass("ImagePickerDropped");
		} else if (this.elDropped) {
			this.el.removeClass("ImagePickerDropped");
		}

		if (!noUpdate) {
			this.updateXmlString();
		}
	},

	isClone: function() {
		return !Photo.isCloneId(this.originalId);
	},

	updateXmlString: function() {
		this.xmlString = "<dtDigiPicsData><ImageID>" + this.id + "</ImageID><TemplateID>" + this.template.id + "</TemplateID><CopyCount>" + this.copyCount + "</CopyCount><Dropped>" + (this.dropped ? "true" : "false") + "</Dropped><Quality>" + this.quality + "</Quality><OriginalImageID>" + this.originalId + "</OriginalImageID><CropX>" + this.cropRect.x + "</CropX><CropY>" + this.cropRect.y + "</CropY><CropWidth>" + this.cropRect.w + "</CropWidth><CropHeight>" + this.cropRect.h + "</CropHeight></dtDigiPicsData>";
	}
}, {
	fromExisting: function(photo, template, originalId) {
		return new Photo("0", photo.thumbUrl, template, 1,
		                 originalId, photo.originalFileName,
						 photo.oSize.w, photo.oSize.h,
						 photo.quality);
	},
	
	fromXmlNode: function(node, templates) {
		var get = function(name) {
			var els = node.getElementsByTagName(name);
			if (els.length == 0) {
				alert("Missing element " + name + "in input XML");
			} else {
				return els[0].firstChild ? els[0].firstChild.nodeValue : "";
			}
		};
		return new Photo(get("ImageID"), get("ThumbUrl"), templates[get("TemplateID")],
		                 get("CopyCount"), get("OriginalImageID"), get("OriginalFileName"),
						 get("OriginalWidth"), get("OriginalHeight"), get("Quality"),
						 get("Dropped"));
	},

	isCloneId: function(id) {
		return (id == "0" || id == "00000000-0000-0000-0000-000000000000");
	}
});

lclass("Template", {
	cons: function(id, name, width, height, listImgWidth) {
		this.id = id;
		this.name = name;
		this.width = parseFloat(width);
		this.height = parseFloat(height);
		this.ratio = this.width / this.height;
		
		this.listImgSize = {w: Math.floor(listImgWidth),
		                    h: Math.floor(listImgWidth / this.ratio)};
	}
}, {
	fromXmlNode: function(node, listImgWidth) {
		var get = function(name) {
			var els = node.getElementsByTagName(name);
			if (els.length == 0) {
				alert("Missing element " + name + " in input XML");
			} else {
				return els[0].firstChild.nodeValue;
			}
		};
		return new Template(get("TemplateID"), get("TemplateName"),
		                    get("TemplateWidth"), get("TemplateHeight"),
							listImgWidth);
	}
});

lclass("ImagePicker", {
	cons: function(params) {
		$PM(this, params, {getXmlUrl: "", setXmlUrl: "", continueOrderUrl: "", listImgWidth: 130, actionsImgWidth: 500, updateInterval: 5000, keepAliveInterval: 300000, qualityLevels: [0, 0, 0, 0, 0,]});
		
		this.elroot = $("ImagePicker");
		this.elactions = $("ImagePickerActions");
		this.openImage = null;
		this.templateEls = {};
		this.templates = {};
		this.photos = [];
		this.changes = false;
		this.leavingPage = false;

		this.el = {}
		var ids = ["ActionsHeading", "ActionsHeadingText", "ActionsImage", "ActionsSizeDisplay", "ActionsFileName", "ActionsQualityText", "ActionsQualityMeter", "ActionsCopyCountDisplay", "ActionsCopyCountArrows", "ActionsDrop", "ActionsDropped", "ActionsTemplate", "ActionsBar", "ActionsShadeTop", "ActionsShadeRight", "ActionsShadeBottom", "ActionsShadeLeft", "ActionsMessage", "ImagePickerNoImages"], i;
		for (i = 0; i < ids.length; i++) {
			this.el[ids[i]] = $(ids[i]);
		}
		this.el["ActionsSizeTBody"] = $S("#ActionsSizeTable>tbody");

		this.req = new LXMLHttp();
		this.req.attachEvent("success", this, this.xmlSent);
		this.req.attachEvent("error", this, this.xmlSendingError);

		this.eldisabled = $("UiDisabled");
		
		this.setDisabled(true);
		
		this.actionsDragging = false;
		this.el.ActionsHeading.attachEvent("mousedown", this, this.actionsStartDrag);
		this.elactions.attachEvent("click", this, function(e) { e.stop(); });
		$("ActionsClose").attachEvent("click", this, this.closeActions);
		$("ActionsClose2").attachEvent("click", this, this.closeActions);
		$("ActionsDrop").attachEvent("click", this, this.dropUndrop);
		$("ActionsClone").attachEvent("click", this, this.clonePhoto);
		$("ActionsCopyCountUp").attachEvent("click", this, this.changeCopyCountUp);
		$("ActionsCopyCountDown").attachEvent("click", this, this.changeCopyCountDown);
		// Firefox sends two click events and a dblclick event but IE
		// sends one click event and one dblclick event... without this, 
		// double clicking would either add too much or too little in
		// some browser.
		if (ImagePicker.IE) {
			$("ActionsCopyCountUp").attachEvent("dblclick", this, function() { return this.changeCopyCount(1); });
			$("ActionsCopyCountDown").attachEvent("dblclick", this, function() { return this.changeCopyCount(-1); });
		}

		this.el.ActionsImage.attachEvent("load", this, this.updateCropShaders);

		// JS position: fixed; only if older than IE7
		if (ImagePicker.IE6) {
		  	this.elactionsparent = new LElementNode("div");
			this.elactionsparent.apply({position: "absolute", left: "0px", top: "0px"});
			this.elactions.style().position = "absolute";
			this.elactionsparent.insertBefore(this.elactions);
			this.elactionsparent.append(this.elactions);
			new LTimer(10, this, this.updateActionsPosition).setRepeat(true).start();
			lwindow.attachEvent("resize", this, this.updateActionsPosition);
		}
		
		this.messageanim = new LAnimation([
			[this.el.ActionsMessage, 
				[0, "opacity: 0.0"],
				[500, "opacity> 0.8"],
				[4000, "opacity: 0.8"],
				[5000, "opacity> 0.0"]
			]
		]);
		
		this.updateCropShadersTimer = new LTimer(5, this, this.updateCropShaders);
		this.centerActionsTimer = new LTimer(50, this, this.centerActions);
		this.trickleLoadTimer = new LTimer(1, this, this.trickleLoadPhotos);

		this.lastUpdate = new Date().getTime();

		this.updateTimer = new LTimer(this.updateInterval, this, this.timerSendXml);

		this.doNotUpdate = false;
		this.firstRequest = true;
	},

	requestXml: function() {
		// Clobber the stored scroll position to avoid nasty flickering
		// and jumping while loading images

		new LTimer(5, function() { window.scroll(0, 0); }).start();

		this.getXml();
	},

	getXml: function() {
		var req = LXMLHttp.createAndOpen("GET", this.getXmlUrl, true);
		req.attachEvent("success", this, this.xmlLoaded);
		req.attachEvent("error", this, this.xmlLoadingError);
		req.send();
	},

	reportServerError: function(doc) {	    
		if (!doc) {
			alert("XML error (no document?)");
			this.handleFatalServerError();
			return;
		}
		var root = doc.documentElement;
		if (root) {
		    var sMessage;
		    if (!root.getElementsByTagName("Msg")[0].firstChild) {
		        sMessage = "MSG is missign!";
		    } else {
		        sMessage = root.getElementsByTagName("Msg")[0].firstChild.nodeValue;
			}
		    if (!root.getElementsByTagName("ErrorDescr")[0].firstChild) {
		    
		    } else {
		        sMessage = sMessage + " (" + root.getElementsByTagName("ErrorDescr")[0].firstChild.nodeValue + ")";
			}
			
			alert(sMessage);
		} else {
			alert("XML error (no root node?)");
		}
		this.handleFatalServerError();
	},

	xmlLoaded: function(e) {
		var node, templateId, templateName, ul, select, photo, arrows, up, down;
		var photoEl, fileEl;
		this.doc = e.getAttribute("req").responseXML;

		if (!this.doc) {
			alert("Unexpected error while loading XML (no .responseXML)");
			this.handleFatalServerError();
			return false;
		}
		if (this.doc.documentElement.nodeName.toLowerCase() == "error") {
			this.reportServerError(this.doc);
			return false;
		}

		var get = function(node, name) {
			var els = node.getElementsByTagName(name);
			if (els.length == 0) {
				alert("Missing element " + name + "in input XML");
			} else {
				return els[0].firstChild.nodeValue;
			}
		};

		for (node = this.doc.documentElement.firstChild; node; node = node.nextSibling) {
			switch (node.nodeName) {
				case "dtTemplate":
					var template = Template.fromXmlNode(node, this.listImgWidth);
					this.templates[template.id] = template;
					this.templateEls[template.id] = new LElementNode("div", {style: "display: none;"},
						new LElementNode("h3",		
							new LElementNode("div", {_class: "TitleText"}, template.name + ImagePicker.LANG["TemplateTitlePictures"]),
							new LElementNode("div", {_class: "CopyCountArrowContainer"},
								arrows = new LElementNode("div", {_class: "CopyCountArrows"},
									up = new LElementNode("a", {_class: "CopyCountUp", href: "#"}),
									down = new LElementNode("a", {_class: "CopyCountDown", href: "#"})
								),
								ImagePicker.LANG["ChangeAllCopyCount"]
							)
						),
						ul = new LElementNode("ul"),
						new LElementNode("div", {_class: "ImagePickerGroupFooter"}, 
							photoEl = new LElementNode("div", {_class: "ImagePickerPhotoAmount"}),
							fileEl = new LElementNode("div", {_class: "ImagePickerFileAmount"})
						)
					);
					this.templateEls[template.id].ul = ul;
					this.elroot.append(this.templateEls[template.id]);
					arrows.templateId = template.id;
					this.templateEls[template.id].arrows = arrows;
					this.templateEls[template.id].photoEl = photoEl;
					this.templateEls[template.id].fileEl = fileEl;

					up.attachEvent("click", this, this.changeAllCopyCountUp);
					down.attachEvent("click", this, this.changeAllCopyCountDown);
					if (ImagePicker.IE) {
						up.attachEvent("dblclick", this, this.changeAllCopyCountUp);
						down.attachEvent("dblclick", this, this.changeAllCopyCountDown);
					}
					
					this.el.ActionsTemplate.append(new LElementNode("option", {value: template.id}, template.name));
					break;
			}
		}
		
		this.node = this.doc.documentElement.firstChild;
		this.noPhotos = true;
		this.trickleLoadTimer.start();

		this.updateSizeDisplay();
		
		this.updateTimer.start();
	},

	trickleLoadPhotos: function() {
		var i = 0;
		for (; this.node; this.node = this.node.nextSibling) {
			switch (this.node.nodeName) {
				case "dtDigiPicsData":
					photo = Photo.fromXmlNode(this.node, this.templates);
					this.photos.push(photo);
					photo.el.attachEvent("click", this, this.listPhotoClick);
					this.templateEls[photo.template.id].ul.append(photo.el);
					i++;
					this.noPhotos = false;
					break;
			}
			if (i >= 20) {
				this.node = this.node.nextSibling;
				this.trickleLoadTimer.start();
				this.updateSizeDisplay();
				break;
			}
		}

		if (!this.node) {
			this.node = null;
			this.doc = null;
			this.updateSizeDisplay();

			if (this.noPhotos) {
				this.el.ImagePickerNoImages.style().display = "block";
				if (window.popUp) {
					window.popUp("ImageUpload.aspx");
				}
			}
		}
		
		if (this.disabled) {
		    this.setDisabled(false);
		}
	},

	xmlLoadingError: function(e) {
		alert("Error loading XML!" + e.getAttribute("req").statusText);
		this.handleFatalServerError();
	},

	timerSendXml: function() {
		if (!this.leavingPage) {
			this.sendXml();
		}
	},

	sendXml: function() {
		var elapsed = new Date().getTime() - this.lastUpdate;
		
		if (this.doNotUpdate || (!this.leavingPage && !this.dirty && elapsed < this.keepAliveInterval)) {
			this.updateTimer.start();
			return;
		}
		
		this.req.abort();
		this.req.open("POST", this.setXmlUrl, true, false);

		var xmlString = "<DocumentElement><Status>" + ((this.leavingPage && this.leavePageFinal) ? "final" : "update") + "</Status>";
		var i;

		for (i = 0; i < this.photos.length; i++) {
			xmlString += this.photos[i].xmlString;
		}

		xmlString += "</DocumentElement>";

		this.dirty = false;
		
		this.req.setRequestHeader("Content-type", "text/xml");
		this.req.send(xmlString);
	},

	xmlSent: function(e) {
		var req = e.getAttribute("req");
		var error = false;
		if (!req.responseXML || !req.responseXML.documentElement
			|| req.responseXML.documentElement.nodeName.toLowerCase() == "error")
		{
			this.reportServerError(req.responseXML);
			return false;
		}
		var root = req.responseXML.documentElement;
		if (this.leavingPage) {
			window.location = this.leavePageUrl;
		} else {
			this.lastUpdate = new Date().getTime();
			this.updateTimer.start();
		}
	},

	xmlSendingError: function(e) {
		if (this.leavingPage) {
			this.sendXml();
		} else {
			this.updateTimer.start();
		}
	},

	setDisabled: function(disabled) {
		this.disabled = disabled;
		//this.eldisabled.style().display = disabled ? "block" : "none";
		set_ui_disabled_visibility(disabled);
		if (disabled && this.openPhoto) {
			this.closeActions();
		}
	},

	leavePage: function(url, isFinal) {
		if (this.disabled) {
			return false;
		}
		
		this.req.abort();
		this.setDisabled(true);
		this.leavingPage = true;
		this.leavePageUrl = url;
		this.leavePageFinal = isFinal;
		this.doNotUpdate = false;
		this.sendXml();

		return false;
	},

	updateSizeDisplay: function() {
		var templateId, i, maxCopyCount, numFiles, numPhotos;
		
		for (templateId in this.templateEls) {
			found = false;
			maxCopyCount = -1;
			numFiles = 0;
			numPhotos = 0;
			for (i = 0; i < this.photos.length; i++) {
				if (this.photos[i].template.id == templateId) {
					numFiles++;
					numPhotos += this.photos[i].copyCount;
					if (this.photos[i].copyCount > maxCopyCount) {
						maxCopyCount = this.photos[i].copyCount;
					}
				}
			}
			
			this.templateEls[templateId].arrows.setClass("CopyCountArrows" + (maxCopyCount == 1 ? " Disabled" : ""));
			this.templateEls[templateId].style().display = (numFiles > 0 ? "block" : "none");

			this.templateEls[templateId].photoEl.setText(
				ImagePicker.LANG["GroupFooterPhotos"].format(this.templates[templateId].name, numPhotos)
			);
			this.templateEls[templateId].fileEl.setText(
				ImagePicker.LANG["GroupFooterFiles"].format(numFiles)
			);
		}
	},

	actionsStartDrag: function(e) {
		ldocument.attachEvent("mousemove", this, this.actionsUpdateDrag);
		ldocument.attachEvent("mouseup", this, this.actionsEndDrag);
		
		var mpos = e.clientMousePosition();
		var apos = this.elactions.position();

		this.dragd = {x: mpos.x - apos.x, y: mpos.y - apos.y};

		return false;
	},

	actionsUpdateDrag: function(e) {
		var pos = this.actionsGetMousePos(e);

		this.elactions.apply({left: (pos.x - this.dragd.x) + "px",
		                      top: (pos.y - this.dragd.y) + "px"});

		return false;
	},

	actionsEndDrag: function(e) {
		ldocument.detachEvent("mousemove", this, this.actionsUpdateDrag);
		ldocument.detachEvent("mouseup", this, this.actionsEndDrag);
		this.actionsDragging = false;

		return false;
	},

	actionsGetMousePos: function(e) {
		var pos = e.clientMousePosition();
		/*@cc_on
		  @if (@_jscript_version < 5.7)
		    var cpos = ldocument.scrollPosition();
			pos.y -= cpos.y;
			pos.x -= cpos.x;
		  @end
		@*/
		return pos;
	},

	listPhotoClick: function(e) {
		if (this.disabled) {
			return false;
		}
		
		if (this.openPhoto) {
			// IE lets users click elements /through/ the actions box o_O
			// let's not let that happen:
			
			var pos = e.clientMousePosition();
			/*@cc_on
			  @if (@_jscript_version < 5.7)
			    pos = e.mousePosition();
			  @end
			@*/
			var geo = this.elactions.geometry();
//			window.status += pos.y + " " + geo.y1 + "  :: ";

			if (pos.x >= geo.x1 && pos.x <= geo.x2 && pos.y >= geo.y1 && pos.y <= geo.y2) {
				return false;
			}
		}

		this.openActions(e.thisElement().obj);

		return false;
	},

	sizeTableLinkClick: function(e) {
		if (this.disabled) {
			return false;
		}

		this.openActions(e.thisElement().obj);

		return false;
	},

	openActions: function(photo) {
		if (!this.openPhoto) {
			this.elactions.style().display = "block";
			this.centerActionsTimer.start();
		}

		this.openPhoto = photo;
		this.openPhoto.el.addClass("ImagePickerImageOpen");
		this.updateActions();
	},

	updateActions: function() {
		this.el.ActionsImage.setAttribute("src", this.openPhoto.thumbUrl);
		this.updateActionsDropped();
		this.updateActionsCopyCount();
		this.updateActionsTable();
		this.el.ActionsSizeDisplay.setText(this.openPhoto.template.name);
		this.el.ActionsHeadingText.setText(this.openPhoto.originalFileName);
		this.el.ActionsFileName.setText(this.openPhoto.originalFileName);
		this.el.ActionsQualityText.setText(ImagePicker.LANG["QualityTexts"][this.openPhoto.quality]);
		this.el.ActionsQualityMeter.setClass("ImagePickerQuality" + this.openPhoto.quality);
	/*	if (this.openPhoto.lowquality) {
			this.elactions.addClass("ImagePickerLowQuality");
		} else {
			this.elactions.removeClass("ImagePickerLowQuality");
		}*/
		
		var rDim = this.el.ActionsBar.dimensions();
		var imgDim = this.el.ActionsImage.dimensions();
		var w = rDim.w + imgDim.w + 40; // >_>
		this.elactions.style().width = w + "px";
		
		this.updateCropShadersTimer.start();
	},

	updateActionsCopyCount: function() {
		if (this.openPhoto) {
			this.el.ActionsCopyCountDisplay.setText(this.openPhoto.copyCount);
			this.el.ActionsCopyCountArrows.setClass("CopyCountArrows" + (this.openPhoto.copyCount > 1 ? "" : " Disabled"));
		}
	},

	updateActionsDropped: function() {
		if (this.openPhoto) {
			this.el.ActionsDrop.setText(
				this.openPhoto.dropped ? ImagePicker.LANG["UndropFile"] : ImagePicker.LANG["DropFile"]
			);
			if (this.openPhoto.dropped) {
				this.elactions.addClass("ImagePickerDropped");
			} else {
				this.elactions.removeClass("ImagePickerDropped");
			}
			this.el.ActionsDropped.style().display = this.openPhoto.dropped ? "block" : "none";
		}
	},

	updateActionsTable: function() {
		if (!this.openPhoto) {
			return false;
		}

		var tr, a, i, odd = true, photo, list, node;

		while (node = this.el.ActionsSizeTBody.firstChild().nextSibling()) {
			node.removeSelf();
		}

		list = [];
		for (i = 0; i < this.photos.length; i++) {
			photo = this.photos[i];

			if (photo.actualId == this.openPhoto.actualId) {
				list.push(photo);
			}
		}

		list.sort(function(a, b) {
			return a.template.id > b.template.id ? 1 : (a.template.id < b.template.id ? -1 : 0);
		});
		
		for (i = 0; i < list.length; i++) {
			photo = list[i];

			tr = new LElementNode("tr", {_class: (photo.template.id == this.openPhoto.template.id ? " CurrentPhoto" : "") + (odd ? " OddRow" : "")},
				new LElementNode("td", {_class: "ActionsSizeCol"},
					a = new LElementNode("a", {href: "#"}, photo.template.name)
				),
				new LElementNode("td", {_class: "ActionsAmountCol"}, (photo.dropped ? "0": photo.copyCount))
			);

			a.obj = photo;
			a.attachEvent("click", this, this.sizeTableLinkClick);

			this.el.ActionsSizeTBody.append(tr);
			
			odd = !odd;
		}
	},

	updateCropShaders: function() {
		if (this.openPhoto) {
			var imgDim = this.el.ActionsImage.dimensions();

			var scale = imgDim.w / this.openPhoto.oSize.w;
			var top = Math.floor(scale * this.openPhoto.cropRect.y);
			var left = Math.floor(scale * this.openPhoto.cropRect.x);
			var right = Math.floor(scale * (this.openPhoto.oSize.w - this.openPhoto.cropRect.w - this.openPhoto.cropRect.x));
			var bottom = Math.floor(scale * (this.openPhoto.oSize.h - this.openPhoto.cropRect.h - this.openPhoto.cropRect.y));
			
			if (top > 0) {
				this.el.ActionsShadeTop.style().height = Math.floor(top) + "px";
				this.el.ActionsShadeTop.style().display = "block";
			} else {
				this.el.ActionsShadeTop.style().display = "none";
			}
			if (bottom > 0) {
				this.el.ActionsShadeBottom.style().height = Math.floor(bottom) + "px";
				this.el.ActionsShadeBottom.style().display = "block";
			} else {
				this.el.ActionsShadeBottom.style().display = "none";
			}
			if (left > 0) {
				this.el.ActionsShadeLeft.style().width = Math.floor(left) + "px";
				this.el.ActionsShadeLeft.style().display = "block";
			} else {
				this.el.ActionsShadeLeft.style().display = "none";
			}
			if (right > 0) {
				this.el.ActionsShadeRight.style().width = Math.floor(right) + "px";
				this.el.ActionsShadeRight.style().display = "block";
			} else {
				this.el.ActionsShadeRight.style().display = "none";
			}
		}
	},

	centerActions: function() {
		var wp = ldocument.viewportSize();
		var dim = this.elactions.dimensions();
		
		var y = Math.max(Math.floor((wp.h - dim.h) / 2), 0);
		var x = Math.min(Math.max(Math.floor((wp.w - this.elactions.offsetWidth()) / 2), 30), wp.w - 30);

		this.elactions.apply({left: x + "px", 
		                      top: y + "px"});
	},

	closeActions: function() {
		if (this.openPhoto) {
			this.elactions.style().display = "none";
			this.openPhoto.el.removeClass("ImagePickerImageOpen");
			this.openPhoto = null;
		}

		return false;
	},
	
	// Emulate position: fixed; in IE6
	updateActionsPosition: function() {
		var scroll = ldocument.scrollPosition();

		this.elactionsparent.style().top = scroll.y + "px";
	},

	dropUndrop: function() {
		if (this.disabled) {
			return false;
		}

		if (this.openPhoto) {
			this.setOpenPhotoDropped(!this.openPhoto.dropped);
			if (this.openPhoto && this.openPhoto.dropped) {
				this.closeActions();
			}
		}

		return false;
	},

	setOpenPhotoDropped: function(dropped) {
		if (dropped) {
			if (this.openPhoto.isClone()) {
				this.openPhoto.destroy();
				this.photos.remove(this.openPhoto);
				this.closeActions();
				this.updateSizeDisplay();
			} else {
				this.openPhoto.setDropped(true);
/*				this.updateActionsDropped();
				this.updateActionsTable();*/
			}
		} else {
			this.openPhoto.setDropped(false);
			this.updateActionsDropped();
			this.updateActionsTable();
		}
		
		this.dirty = true;
	},

	clonePhoto: function() {
		if (this.disabled) {
			return false;
		}

		if (this.openPhoto) {
			this.dirty = true;
			
			var templateId = this.el.ActionsTemplate.value();
			if (this.openPhoto.template.id == templateId) {
				this.openPhoto.setCopyCount(this.openPhoto.copyCount + 1);
				this.updateActions();
				return false;
			}
			var i, photo;
			for (i = 0; i < this.photos.length; i++) {
				photo = this.photos[i];
				
				if (photo.actualId == this.openPhoto.actualId && photo.template.id == templateId)
				{
					photo.setCopyCount(photo.copyCount + 1);
					this.updateSizeDisplay();
					this.updateActionsTable();
					return false;
				}
			}
			var originalId = (Photo.isCloneId(this.openPhoto.originalId) ? this.openPhoto.id : this.openPhoto.originalId);
			photo = Photo.fromExisting(this.openPhoto, this.templates[templateId], originalId);
			photo.calculateQuality(this.qualityLevels);
			this.photos.push(photo);
			photo.el.attachEvent("click", this, this.listPhotoClick);
			this.templateEls[templateId].ul.append(photo.el);
			this.updateSizeDisplay();
			this.updateActionsTable();
			this.messageanim.start();
		}

		return false;
	},

	changeCopyCountUp: function() { return this.changeCopyCount(1); },
	changeCopyCountDown: function() { return this.changeCopyCount(-1); },

	changeCopyCount: function(d) {
		if (this.disabled) {
			return false;
		}
		
		if (this.openPhoto.dropped) {
			if (d == 1) {
				this.setOpenPhotoDropped(false);
			} else {
				return false;
			}
		}
		this.dirty = true;
		if (this.openPhoto.copyCount <= 1 && d == -1) {
			return false;
		}
		this.openPhoto.setCopyCount(this.openPhoto.copyCount + d);
		this.updateActionsCopyCount();
		this.updateSizeDisplay();
		this.updateActionsTable();

		return false;
	},

	changeAllCopyCountUp: function(e) { return this.changeAllCopyCount(e, 1); },
	changeAllCopyCountDown: function(e) { return this.changeAllCopyCount(e, -1); },

	changeAllCopyCount: function(e, d) {
		if (this.disabled) {
			return false;
		}

		var templateId = e.thisElement().parentNode().templateId;

		var i, photo;
		for (i = 0; i < this.photos.length; i++) {
			photo = this.photos[i];
			if (photo.template.id == templateId) {
				if (d > 0) {
					photo.setCopyCount(photo.copyCount + d);
				} else if (photo.copyCount > -d) { // d <= 0
					photo.setCopyCount(photo.copyCount + d);
				}
			}
		}

		this.updateActionsCopyCount();
		this.updateSizeDisplay();
		this.updateActionsTable();
		this.dirty = true;
		
		return false;
	},
	
	handleFatalServerError: function() {
	    this.setDisabled(false);
	    location.reload();
	}
}, {
	LANG: {
		DropFile: "Drop file",
		UndropFile: "Undrop file",
		TemplateTitlePictures: ":",
		QualityTexts: ["very good", "good", "average", "bad", "very bad"],
		Dropped: "DROPPED",
		ChangeAllCopyCount: "Muuta jokaisen kuvan kappalemäärää: ",
		GroupFooterPhotos: "{0} photos: {1} pcs",
		GroupFooterFiles: "Files: {0} pcs"
	},

	MM_PER_INCH: 25.4
});

lclass("XMLHelper", {}, {
    escapeXML: function(s) {
        return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
    }
});

// Some conditional compilation for browser detection

/*@cc_on
  ImagePicker.IE = true;
  @if (@_jscript_version < 5.7)
    ImagePicker.IE6 = true;
  @end
@*/
