var __imageUrlPattern = "image/{0}/{1}/{2}";
var __imageTitleFormat = "{0} of {1} {2}";

var __widthGallery1 = 480;
var __heightGallery1 = 420;
var __animationSpeed = 3000;

var __thumbWidth2 = 0;
var __thumbHeight2 = 120;

function Gallery()
{
}

Gallery.current = null;

Gallery.setup = function ()
{
	var elems = dom.getElementsByClassName(document, "gallery", "a");
	for (var i = 0; i < elems.length; i++)
		elems[i].onclick = Gallery.link_onclick;

	var galleryData = document.getElementById("galleryData");
	if (galleryData != null)
	{
		switch (galleryData.className)
		{
			case "gallery-0":
				Gallery.current = new Gallery0();
				break;
			case "gallery-1":
				Gallery.current = new Gallery1();
				break;
			case "gallery-2":
				Gallery.current = new Gallery2();
				break;
		}
		if (Gallery.current != null)
			Gallery.current.initialize(galleryData);
	}
}

Gallery.cleanup = function ()
{
	if (Gallery.current != null)
		Gallery.current.cleanup();
}

Gallery.link_onclick = function ()
{
	var width = null;
	var height = null;

	if (this.className.match(/size-(\d+)-(\d+)/))
	{
		width = parseInt(RegExp.$1);
		height = parseInt(RegExp.$2);
	}

	Gallery.openGalleryDialog(this.href, width, height);
	return false;
}

Gallery.openGalleryDialog = function (href, width, height)
{

	if (width == null || isNaN(width))
		width = 700;
	if (height == null || isNaN(height))
		height = 650;

	ui.showDialog(href, width, height);
}

Gallery.parseData = function (inputControl)
{
	var galleryData = [];

	var items = inputControl.value.trim().split(recordSeparator);
	for (var i = 0; i < items.length; i++)
	{
		var fields = items[i].trim().split(fieldSeparator);
		if (fields.length > 4)
		{
			var item =
			{
				id: fields[0].trim(),
				width: fields[1].trim(),
				height: fields[2].trim(),
				header: fields[3].trim(),
				notes: fields[4].trim()
			};
			galleryData.push(item);
		}
	}

	return galleryData;
}

/**
 * Implements a simple inline gallery
 */
function Gallery0()
{
	this.galleryData = null;
	this.galleryIndex = 0;
	this.galleryImage = null;
	this.maxWidth = 0;
	this.maxHeight = 0;
}
Gallery0.prototype = new DomDependentDispatcher(Gallery0);
Gallery0.DomElements = {
	"galleryImageTarget":   ["DIV", "galleryImageTarget"],
	"galleryPrev":          ["DIV", "galleryPrev"],
	"galleryNext":          ["DIV", "galleryNext"]
};

Gallery0.prototype.initialize = function (inputControl)
{
	var countMissing = this.initializeElements();
	if (countMissing != 0)
		return;

	this.galleryData = Gallery.parseData(inputControl);
	this.galleryImage = this.controls("galleryImageTarget").getElementsByTagName("IMG")[0];
	this.maxWidth = this.controls("galleryImageTarget").offsetWidth;
	this.maxHeight = this.controls("galleryImageTarget").offsetHeight;

	this.controls("galleryPrev").onclick = createCallback(this, "showPrevGalleryImage");
	this.controls("galleryNext").onclick = createCallback(this, "showNextGalleryImage");
}

Gallery0.prototype.showGalleryImage = function (index)
{
	var item = this.galleryData[index];
	if (item != null)
	{
		this.galleryImage.src = __imageUrlPattern.format(item.id, this.maxWidth, this.maxHeight);
		this.galleryImage.title = item.notes;
	}
}

Gallery0.prototype.showPrevGalleryImage = function ()
{
	this.galleryIndex -= 1;
	if (this.galleryIndex < 0)
		this.galleryIndex = this.galleryData.length - 1;

	this.showGalleryImage(this.galleryIndex);
}

Gallery0.prototype.showNextGalleryImage = function ()
{
	this.galleryIndex += 1;
	if (this.galleryIndex > this.galleryData.length - 1)
		this.galleryIndex = 0;

	this.showGalleryImage(this.galleryIndex);
}

/**
 * Implements a standalone image gallery
 */
function Gallery1()
{
	this.galleryData = null;
	this.galleryIndex = 0;
	this.galleryLoader = new Image;
	this.galleryLoader.onload = createCallback(this, "loader_onload");
	this.galleryLoader.onerror = createCallback(this, "loader_onerror");
}

Gallery1.prototype = new DomDependentDispatcher(Gallery1);
Gallery1.DomElements = {
	"galleryImage":         ["DIV", "galleryImage"],
	"galleryLoading":       ["DIV", "galleryLoading"],
	"galleryText":          ["DIV", "galleryText"],
	"galleryTitle":         ["DIV", "galleryTitle"],
	"galleryPrev":          ["DIV", "galleryPrev"],
	"galleryNext":          ["DIV", "galleryNext"]
};

Gallery1.prototype.initialize = function (inputControl)
{
	var countMissing = this.initializeElements();
	if (countMissing != 0)
		return;

	this.galleryData = Gallery.parseData(inputControl);

	this.controls("galleryPrev").onclick = createCallback(this, "showPrevGalleryImage");
	this.controls("galleryNext").onclick = createCallback(this, "showNextGalleryImage");
}

Gallery1.prototype.loader_onload = function ()
{
	this.showImage();
}

Gallery1.prototype.showImage = function ()
{
	var galleryLoading = this.controls("galleryLoading");
	var galleryImage = this.controls("galleryImage");

	galleryImage.src = this.galleryLoader.src;
	galleryImage.width = this.galleryLoader.width;
	galleryImage.height = this.galleryLoader.height;
	galleryImage.style.display = "block";
	galleryLoading.style.display = "none";
}

Gallery1.prototype.showGalleryImage = function (index)
{
	var item = this.galleryData[index];

	this.galleryLoader.src = __imageUrlPattern.format(item.id, __widthGallery1, __heightGallery1);

	this.controls("galleryText").innerHTML = item.notes;
	this.controls("galleryTitle").innerHTML = __imageTitleFormat.format(
		(index + 1), this.galleryData.length, item.header.length ? " - " + item.header : "");

	var galleryLoading = this.controls("galleryLoading");
	var galleryImage = this.controls("galleryImage");

	galleryLoading.style.width = galleryImage.offsetWidth + "px";
	galleryLoading.style.height = galleryImage.offsetHeight + "px";
	galleryLoading.style.display = "block";
	galleryImage.style.display = "none";
}

Gallery1.prototype.showPrevGalleryImage = function ()
{
	this.galleryIndex -= 1;
	if (this.galleryIndex < 0)
		this.galleryIndex = this.galleryData.length - 1;

	this.showGalleryImage(this.galleryIndex);
}

Gallery1.prototype.showNextGalleryImage = function ()
{
	this.galleryIndex += 1;
	if (this.galleryIndex > this.galleryData.length - 1)
		this.galleryIndex = 0;

	this.showGalleryImage(this.galleryIndex);
}

function Gallery2()
{
	this.thumbbar = null;
	this.galleryData = null;

	this.loader = new Image();
	this.loader.onload = this.loader_onload;

	this.image1 = null;
	this.image2 = null;

	this.currentIndex = -1;

	this.active = -1;
	this.transition = null;
	this.alpha1 = null;
	this.alpha2 = null;
}

Gallery2.prototype = new DomDependentDispatcher(Gallery2);
Gallery2.current = null;
Gallery2.DomElements = {
	"gallery_view":        ["DIV", "gallery_view"],
	"gallery_controls":    ["DIV", "gallery_controls"],
	"gallery_view_images": ["DIV", "gallery_view_images"],
	"gallery_view_header": ["DIV", "gallery_view_header"],
	"gallery_view_text":   ["DIV", "gallery_view_images"],
	"gallery_loading":     ["DIV", "gallery_loading"],
	"gallery_prev":        ["*", "gallery_prev"],
	"gallery_next":        ["*", "gallery_next"],
	"gallery_image1":      ["IMG", "gallery_image1"],
	"gallery_image2":      ["IMG", "gallery_image2"]
};

Gallery2.prototype.initialize = function (inputControl)
{
	var countMissing = this.initializeElements();
	if (countMissing != 0)
		return this.showMissingList();

	var dataCtrl = this.controls("gallery_data");

	this.galleryData = this.parseData(inputControl);

	this.image1 = this.controls("gallery_image1");
	this.image2 = this.controls("gallery_image2");

	evt.addListener(this.controls("gallery_prev"), "onclick", createCallback(this, "showPrev"));
	evt.addListener(this.controls("gallery_next"), "onclick", createCallback(this, "showNext"));

	this.thumbbar = new Thumbbar();
	this.thumbbar.initialize(this.galleryData);
	this.showItem(0);
}

Gallery2.prototype.parseData = function (dataCtrl)
{
	if (dataCtrl == null)
		return;

	var images = [];

	var items = dataCtrl.value.trim().split(recordSeparator);
	for (var i = 0; i < items.length; i++)
	{
		var fields = items[i].trim().split(fieldSeparator);
		if (fields.length > 4)
		{
			var iwidth = parseInt(fields[1].trim());
			var iheight = parseInt(fields[2].trim());
			var dimensions = this.getThumbSize(iwidth, iheight);
			var item =
			{
				id: fields[0].trim(),
				width: dimensions[0],
				height: dimensions[1],
				header: fields[3].trim(),
				notes: fields[4].trim()
			};
			images.push(item);
		}
	}

	return images;
}

Gallery2.prototype.getThumbSize = function (iwidth, iheight)
{
	var ratio = __thumbHeight2 / iheight;
	var width = Math.round(iwidth * ratio);
	return [width, __thumbHeight2];
}

Gallery2.prototype.cleanup = function ()
{
	this.thumbbar.cleanup();
	this.thumbbar = null;
}

Gallery2.prototype.showPrev = function ()
{
	var prev = this.currentIndex > 0 ? this.currentIndex - 1 : this.galleryData.length - 1;
	this.showItem(prev);
}

Gallery2.prototype.showNext = function ()
{
	var next = this.currentIndex < this.galleryData.length - 1 ? this.currentIndex + 1 : 0;
	this.showItem(next);
}

Gallery2.prototype.showItem = function (itemIndex, thumbClick)
{
	if (this.currentIndex == itemIndex)
		return;

	this.currentIndex = parseInt(itemIndex);
	this.thumbbar.focusItem(this.currentIndex, thumbClick, window.createCallback(this, "showCurrentItem"));
}

Gallery2.prototype.showCurrentItem = function ()
{
	this.active = -this.active;

	var image = this.galleryData[this.currentIndex];

	this.showLoading();
	this.loader.src = __imageUrlPattern.format(image.id, __widthGallery1, __heightGallery1);
}

Gallery2.prototype.getCurrentTarget = function ()
{
	if (this.active == 1)
		return this.image2;
	else
		return this.image1;
}

Gallery2.prototype.showImage = function ()
{
	this.hideLoading();

	var target = this.getCurrentTarget();
	target.src = this.loader.src;
	target.width = this.loader.width;
	target.height = this.loader.height;

	this.playTransition();

	var image = this.galleryData[this.currentIndex];

	this.controls("gallery_view_header").innerHTML = image.header;
	this.controls("gallery_view_text").innerHTML = image.notes;
}

Gallery2.prototype.playTransition = function ()
{
	if (this.transition == null)
	{
		this.transition = new anim.Sequence(anim.Sequence.TypeSimultaneous);
		this.alpha1 = new anim.Alpha(this.image1, 100, 1500, Math.easeOutExpo);
		this.alpha2 = new anim.Alpha(this.image2, 100, 1500, Math.easeOutExpo);

		this.transition.addChild(this.alpha1);
		this.transition.addChild(this.alpha2);

		this.alpha1.setAlpha(0);
		this.alpha2.setAlpha(0);
	}

	var twoup = this.image1.src != "about:blank";
	if (twoup)
	{
		this.transition.stop();
		if (this.active == 1)
		{
			this.image1.style.zIndex = 0;
			this.image2.style.zIndex = 1;
			this.alpha1.setEndValue(0);
			this.alpha2.setEndValue(100);
		}
		else
		{
			this.image1.style.zIndex = 1;
			this.image2.style.zIndex = 0;
			this.alpha1.setEndValue(100);
			this.alpha2.setEndValue(0);
		}
		this.transition.run();
		css.show(this.image1);
		css.show(this.image2);
	}
	else
	{
		this.alpha2.run();
		css.show(this.image2);
	}
}

Gallery2.prototype.ontransitioncomplete = function ()
{
	this.transitionPlaying = false;
}

Gallery2.prototype.showLoading = function ()
{
	css.undisplay(this.controls("gallery_controls"));
	css.display(this.controls("gallery_loading"));
}

Gallery2.prototype.hideLoading = function ()
{
	css.display(this.controls("gallery_controls"));
	css.undisplay(this.controls("gallery_loading"));
}

Gallery2.prototype.loader_onload = function ()
{
	Gallery.current.showImage();
}

Gallery2.prototype.loader_onerror = function ()
{
	log.error("Image {0} could not be loaded".format(this.src));
}

/**
 * Encapsulates the thumbbar functionality
 * @constructor
 */
function Thumbbar()
{
	this.moveEngaged = false;
	this.animEngaged = false;
	this.minimized = false;

	this.thumbWidth = 0;
	this.thumbHeight = 120;
	this.thumbMargin = 6;

	this.offsetEdge = 96;
	this.galleryData = null;
}
Thumbbar.prototype = new DomDependentDispatcher(Thumbbar);

Thumbbar.prototype.cleanup = function ()
{
	for (var elementId in Thumbbar.DomElements)
		Thumbbar.DomElements[elementId] = null;

	this.move = null;
}

/**
 * Defines DOM elements used by the thumbbar
 */
Thumbbar.DomElements = {
	"gallery_thumbbar":    ["DIV", "gallery_thumbbar"],
	"gallery_thumbstrip":  ["DIV", "gallery_thumbstrip"]
};

Thumbbar.DIFF_STRIP_WIDTH = 96;

/**
 * Returns a DOM element associated with the supplied ID
 */
Thumbbar.prototype.controls = function (controlID)
{
	return Thumbbar.DomElements[controlID];
}

/**
 * Initializes the thumbbar
 */
Thumbbar.prototype.initialize = function (images, go)
{
	var countMissing = this.initializeElements();
	if (countMissing != 0)
		return this.showMissingList();

	var thumbbar = this.controls("gallery_thumbbar");
	var thumbstrip = this.controls("gallery_thumbstrip");

	this.images = images;
	for (var i = 0; i < this.images.length; i++)
	{
		var img = document.createElement("img");
		img.width = images[i].width;
		img.height = images[i].height;
		img.imageID = images[i].id;
		img.id = "gthumb" + i;

		img.className = "thumb";

		thumbstrip.appendChild(img);
	}

	evt.addHandler(document, "onmousemove", createCallback(this, "doc_onmousemove"));
	evt.addHandler(thumbbar, "onmousemove", createCallback(this, "onmousemove"));
	evt.addHandler(window, "onresize", createCallback(this, "onresize"));

	css.setPixelTop(thumbstrip, 0);
	css.setPixelLeft(thumbstrip, 0);

	this.move = new anim.Move(thumbstrip, 0, 0, 400, Math.easeOutQuint, [this, "stopAnimation"]);
	thumbbar.style.visibility = "visible";

	//this.onresize();
	this.recalculateValues();
	this.loadThumb(0);
	this.initializeThumbs();
	this.recalculateValues();
}

Thumbbar.prototype.loadThumb = function (index)
{
	var image = document.getElementById("gthumb" + index);
	image.src = __imageUrlPattern.format(image.imageID, __thumbWidth2, __thumbHeight2);
	if (index < this.images.length - 1)
		setTimeout(createCallback(this, "loadThumb", [index + 1]), 100);
}

Thumbbar.prototype.recalculateValues = function ()
{
	var thumbbar = this.controls("gallery_thumbbar");
	var thumbstrip = this.controls("gallery_thumbstrip");

	var widthStrip = 0;
	for (var i = 0; i < this.images.length; i++)
		widthStrip += this.images[i].width + this.thumbMargin;

	this._widthStrip = widthStrip + Thumbbar.DIFF_STRIP_WIDTH;
	this._offsetWidth = thumbbar.offsetWidth;

	this._anchorLeft = dom.getLeft(thumbbar) - 2;
	this._trackX = this._widthStrip - this._offsetWidth;

	this._minMouseX = 0;
	this._maxMouseX = thumbbar.offsetWidth;
	this._minMouseY = 0;
	this._maxMouseY = thumbbar.offsetHeight;
}

Thumbbar.prototype.doc_onmousemove = function (e)
{
	var event = util.getEvent(e);
	var thumbbar = this.controls("gallery_thumbbar");
	var thumbstrip = this.controls("gallery_thumbstrip");

	var html = document.getElementsByTagName("html")[0];
	var mouseX = event.clientX - dom.getLeft(thumbbar);
	var mouseY = event.clientY - dom.getTop(thumbbar) + html.scrollTop;
	var moveEngaged = (this._widthStrip > this._offsetWidth) &&
		(mouseX >= this._minMouseX && mouseX <= this._maxMouseX &&
		mouseY >= this._minMouseY && mouseY <= this._maxMouseY);

	if (moveEngaged)
	{
		var targetLeft = this.getTargetThumbstripLeft(mouseX, this.offsetEdge);
		var stripX = parseInt(thumbstrip.style.left) || 0;
		var distanceX = stripX - targetLeft;

		var animEngaged = Math.abs(distanceX) > 10;

		this.moveEngaged = true;
		this.move.setEndValue(targetLeft, 0);
		if (animEngaged && !this.animEngaged)
		{
			this.animEngaged = true;
			this.move.run();
		}
		if (this.moveEngaged && !this.animEngaged)
			css.setPixelLeft(thumbstrip, this.getTargetThumbstripLeft(event.clientX - dom.getLeft(thumbbar), this.offsetEdge));
	}
	else
	{
		this.moveEngaged = false;
	}
}

Thumbbar.prototype.onresize = function ()
{
	this.recalculateValues();
}

Thumbbar.prototype.initializeThumbs = function ()
{
	var thumbstrip = this.controls("gallery_thumbstrip");
	var thumbs = thumbstrip.getElementsByTagName("IMG");

	for (var i = 0; i < thumbs.length; i++)
	{
		thumbs[i].index = i;
		util.applyPrototypes(thumbs[i], ThumbImage);
	}
}

Thumbbar.prototype.stopAnimation = function ()
{
	this.animEngaged = false;
}

Thumbbar.prototype.onmousemove = function (e)
{
	if (this.moveEngaged && !this.animEngaged)
	{
		var event = util.getEvent(e);
		var thumbbar = document.getElementById("gallery_thumbbar");
		var thumbstrip = document.getElementById("gallery_thumbstrip");

		thumbstrip.style.left = this.getTargetThumbstripLeft(event.clientX - dom.getLeft(thumbbar), this.offsetEdge) + "px";
	}

}

/**
 *
 */
Thumbbar.prototype.focusItem = function (itemIndex, thumbClick, oncomplete)
{
	var thumbbar = this.controls("gallery_thumbbar");
	var thumbstrip = this.controls("gallery_thumbstrip");

	var thumbs = thumbstrip.getElementsByTagName("IMG");
	for (var i = 0; i < thumbs.length; i++)
	{
		if (i == itemIndex)
			css.addClassName(thumbs[i], "current");
		else
			css.removeClassName(thumbs[i], "current");
	}

	if (!thumbClick && (this._widthStrip > this._offsetWidth))
	{
		if (itemIndex == 0)
			var targetLeft = 0;
		else if (itemIndex == this.images.length -1)
			var targetLeft = -this._trackX;
		else
			var targetLeft = -(itemIndex * (this._trackX / this.images.length));

		var move1 = new anim.Move(thumbstrip, targetLeft, 0, 500, Math.easeNone, oncomplete);
		move1.run();
	}
	else if (oncomplete)
		oncomplete();
}

/**
 * @param Number mouseX Mouse position relative to the left of the thumbbar.
 * @param Number offsetEdge Amount of offset on both sides between the edge of the thumbbar
 * and the beginning of thumbstrip.
 */
Thumbbar.prototype.getTargetThumbstripLeft = function (mouseX, offsetEdge)
{
	var thumbstrip = this.controls("gallery_thumbstrip");

	var trackX = this._trackX + (offsetEdge);
	var ratio = trackX / this._offsetWidth;
	var point = -(mouseX * ratio) + offsetEdge;

	return Math.round(point);
}

function ThumbImage()
{
}

ThumbImage.prototype.onclick = function ()
{
	Gallery.current.showItem(this.index, true);
}

ThumbImage.prototype.onmouseover = function ()
{
	//css.addClassName(this, "mouseover");
}

ThumbImage.prototype.onmouseout = function ()
{
	//css.removeClassName(this, "mouseover");
}

evt.addHandler(window, "onload", Gallery.setup);
evt.addHandler(window, "onunload", Gallery.cleanup);

