﻿//
//TODO:
//	server-side caching: System.Web.Caching
//		cache files to overcome "Save Picture As..." problems?
//	ExifInfo attributes for non-JPG files?
//	watermarking images
//	different presentation formats/pages:
//		Mobile Me modes (http://gallery.me.com/iben#100048&view=carouseljs&bgcolor=black&sel=0)
//			mosaic (current mode, mix of main image and thumbs)
//			carousel (main image with large thumbs on either side)
//			grid (thumbnails only)
//	Safari clips content with scrollbars
//

var YD = YAHOO.util.Dom,
	YE = YAHOO.util.Event,
	YH = YAHOO.util.History,
//
// Folders - A tree of folders with galleries at the leaves
// .Name - Friendly UI name
// .BasePath - Actual file path to folder or gallery
// .Folders - Array of sub-folders/galleries (n/a for a gallery)
//
	Folders,
//
// Gallery - Info about the currently selected gallery
// .Name - Friendly UI name
// .BasePath - Actual file path to gallery
// .Credit - Default media credit.
// .HasKmlFile - Gallery has a KML file. ('True' or 'False')
// .MediaItems - Array of media items
//		.FileName - File name and extension for media, without path
//		.FilePath - Relative file path (if not present, default to Gallery.BasePath)
//		.FrameName - Image file name to use for thumbnail and main image for non-image media
//		.Title
//		.Credit - if not present, default to Gallery.Credit
//		.Body
//
	Gallery,
//
// ExifInfo - Info about the currently selected media item
//	Fields are determined by the server and just dumped into the ExifInfoPanel for display.
//	
	ExifInfo,
	InitialState = ".",
	RequestedState,
	GalleryPath,
	MediaCnt = 0,
	ImageNum = -1,

	ImageWidths = [100, 400, 600, 800, 1024, 1280, 1600, 1800, 2500],
	ImageHeights = [100, 300, 450, 600, 768, 960, 1200, 1350, 1400],
	ThumbWidthExtra,
	ThumbHeightExtra,
	MainImgWidthExtra,
	MainImgHeightExtra,
	ViewerPadding,
	HeaderHeight,
	FooterHeight,
	NoThumbs = false,
	ThumbsPerPage = 0,
	ThumbsPerRow = 0,
	DesiredThumbsPerRow = 3,
	MinThumbsPerRow = 2,
	MainImageSize = -1,
	PageNum = 0,
	NumPages = 0,
	HistoryModuleName = "item",
	pagePicker,
	pagePickerShown = false,
	galPicker,
	galPickerShown = false,
	ExifInfoPanel,
	ExifInfoPanelShown = false,
	ExifInfoPanelHiding = false,
	ExifInfoPanelPos,
	ExifInfoPath,		 		// the path for which the most recent ExifInfo was received
	ExifInfoPanelBuilt = false, // true when the panel contains the tabular info for the ExifInfoPath
	WaitingExifInfo = false,
	SlideShowRunning = false,
	SlideShowTimerID = -1,
	SlideShowInterval = 5000,
	delaySelector,
	delaySelectorShown,
	delaySelectorPos,
	delaySlider,
	pathSep = "/";

var MediaCallbacks = {
	success: function(o)
	{
		// Use the JSON Utility to parse the Media data returned from the server
		try
		{
			var data = YAHOO.lang.JSON.parse(o.responseText);
		}
		catch (x)
		{
			alert("JSON Parse failed for Media data:" + "\r\n\r\n" + o.responseText);
			return;
		}
		Gallery = data.d;
		MediaCnt = Gallery.MediaItems.length; 
		EnterRequestedState();
	},

	failure: function(o)
	{
		if (!YAHOO.util.Connect.isCallInProgress(o))
		{
			alert("Media data request failed!" + "\r\n\r\n" + o.responseText);
		}
	},

	timeout: 10000
};

var GalleryCallbacks = {
	success: function(o)
	{
		// Use the JSON Utility to parse the Gallery data returned from the server
		try
		{
			var data = YAHOO.lang.JSON.parse(o.responseText);
		}
		catch (x)
		{
			alert("JSON Parse failed for Gallery data:" + "\r\n\r\n" + o.responseText);
			return;
		}
		Folders = data.d;
		EnterRequestedState();
	},

	failure: function(o)
	{
		if (!YAHOO.util.Connect.isCallInProgress(o))
		{
			alert("Gallery data request failed!" + "\r\n\r\n" + o.responseText);
		}
	},

	timeout: 10000
};

var InfoCallbacks = {
	success: function(o)
	{
		// Use the JSON Utility to parse the Gallery data returned from the server
		try
		{
			var data = YAHOO.lang.JSON.parse(o.responseText);
		}
		catch (x)
		{
			alert("JSON Parse failed for Gallery data:" + "\r\n\r\n" + o.responseText);
			return;
		}
		ExifInfo = data.d;
		if (WaitingExifInfo)
		{
			WaitingExifInfo = false;
			ShowExifInfoPanel();
		}
	},

	failure: function(o)
	{
		if (!YAHOO.util.Connect.isCallInProgress(o))
		{
			alert("Gallery data request failed!" + "\r\n\r\n" + o.responseText);
		}
	},

	timeout: 10000
};

function RequestNewState(state)
{
	RequestedState = state;
	EnterRequestedState();
}

function EnterRequestedState()
{
	CloseGalPicker(false);
	ClosePagePicker(false);
	if (RequestedState == "." && Folders != undefined)
		RequestedState = Folders.Name;
	if (RequestedState == undefined)
		return;
	if (Folders == undefined)
	{
		// request Folders data
		YAHOO.util.Connect.setDefaultPostHeader(false);
		YAHOO.util.Connect.initHeader("Content-Type", "application/json; charset=utf-8", true);
		YAHOO.util.Connect.asyncRequest('POST', "WebService.asmx/GetGalleries", GalleryCallbacks);
		return;
	}
	var parts = SplitItemName(RequestedState);
	if (parts.path != GalleryPath)
	{
		var folder = FindFolder(Folders, parts.path);
		if (folder == null)
		{
			// can't find specified folder, default to root
			YH.navigate(HistoryModuleName, Folders.Name);
			return;
		}
		Gallery = undefined;
		MediaCnt = 0;
		ThumbsPerPage = 0;
		SetMainImageNum(-1);
		SetGalleryTracks(parts.path);
		if (folder.Folders != undefined && folder.Folders != null)
		{
			GalleryPath = "";
			// this is a folder and not a gallery, display the gallery picker
			RequestedState = undefined;
			CalcLayout();
			ShowGalPicker(parts.path);
			return;
		}
		else
		{
			// request Media data
			GalleryPath = parts.path;
			YAHOO.util.Connect.setDefaultPostHeader(false);
			YAHOO.util.Connect.initHeader("Content-Type", "application/json; charset=utf-8", true);
			var req = { "RelPath": folder.BasePath };
			var s = YAHOO.lang.JSON.stringify(req);
			YAHOO.util.Connect.asyncRequest('POST', 'WebService.asmx/GetMedia', MediaCallbacks, s);
			return;
		}
	}
	CalcLayout();
	if (parts.filename != null)
	{
		// a filename was supplied, try to select it
		var name = parts.filename;
		for (var i = 0; i < MediaCnt; ++i)
		{
			if (Gallery.MediaItems[i].FileName == name)
			{
				SetMainImageNum(i);
				RequestedState = undefined;
				return;
			}
		}
		// couldn't find specified name, pick the first item
		Navigate(0);
		return;
	}
	// no filename supplied
	// don't clutter history with redundant navigation, just set image
	SetMainImageNum(0);
}

function SetGalleryTracks(path)
{
	var div = YD.get('galleryTracks');
	while (div.hasChildNodes())
	{
		div.removeChild(div.childNodes[0]);
	}
	var span = document.createElement('span');
//	SetupButton(span, '<home>');
	YD.addClass(span, 'track');
	span.innerHTML = '<a href="http://www.ForestMoon.com/">Forest Moon</a>&nbsp;&gt;&nbsp;';
	div.appendChild(span);
	var splitPath = path.split(pathSep);
	var href = '';
	for (var i = 0; i < splitPath.length; ++i)
	{
		if (i < splitPath.length - 1)
		{
			span = document.createElement('span');
			if (i > 0)
				href += pathSep;
			href += splitPath[i];
			SetupButton(span, href);
			YD.addClass(span, 'track');
			span.innerHTML = splitPath[i] + '&nbsp;&gt;&nbsp;';
			div.appendChild(span);
		}
		else
		{
			var span = document.createElement('span');
			span.innerHTML = splitPath[i];
			div.appendChild(span);
		}
	}
}

function FindFolder(folder, name)
{
	var splitPath = name.split(pathSep);
	if (splitPath[0] != folder.Name)
	{
		return null;
	}
	if (splitPath.length == 1)
		return folder;
	if (folder.Folders == undefined || folder.Folders == null)
	{
		return null;
	}
	var s = name.substr(splitPath[0].length + 1);
	for (var i = 0; i < folder.Folders.length; ++i)
	{
		var found = FindFolder(folder.Folders[i], s);
		if (found != null)
		{
			return found;
		}
	}
	return null;
}

function SplitItemName(name)
{
	var ret = { "path": name, "filename": null };
	var splitPath = name.split(pathSep);
	var dot = splitPath[splitPath.length - 1].indexOf(".");
	if (dot != -1)
	{
		ret.filename = splitPath[splitPath.length - 1];
		ret.path = name.substr(0, name.length - ret.filename.length - 1);
	}
	return ret;
}

function ItemReady()
{
	RequestNewState(YH.getCurrentState(HistoryModuleName));
}

// return the relative file name for a still image to use for the Media item
function MediaFrameName(inx)
{
	// use the FrameName if it is specified, otherwise the FileName is its own image
	var name = Gallery.MediaItems[inx].FrameName || Gallery.MediaItems[inx].FileName;
	return (Gallery.MediaItems[inx].FilePath || Gallery.BasePath) + pathSep + name;
}

// return the relative file name for the actual media file for the Media item
function MediaFileName(inx)
{
	// use the FrameName if it is specified, otherwise the FileName is its own image
	var name = Gallery.MediaItems[inx].FileName;
	return (Gallery.MediaItems[inx].FilePath || Gallery.BasePath) + pathSep + name;
}

// return the # path name to the Media item, e.g. Galleries\<gallery name>...\<FileName>
function MediaItemName(inx)
{
	return GalleryPath + pathSep + Gallery.MediaItems[inx].FileName;
}

function Navigate(inx)
{
	YH.navigate(HistoryModuleName, MediaItemName(inx));
}

function page_load()
{
	if (false)	// YUI logging
	{
		var d1 = document.body.appendChild(document.createElement("div"));
		YD.addClass(d1, "yui-skin-sam");	// adding this to the BODY throws a LOT of stuff off
		var d2 = d1.appendChild(document.createElement("div"));
		new YAHOO.widget.LogReader(d2);
	}

	getSizes();

	// listeners to handle resizing
	YE.addListener(window, 'maximize', CalcLayout, this, true);
	YE.addListener(window, 'resize', CalcLayout, this, true);

	// listeners to manage mouseover border swapping
	YE.addListener('viewer', 'mouseover', Image_Mouseover);
	YE.addListener('viewer', 'mouseout', Image_Mouseout);

	InitialState = YH.getBookmarkedState(HistoryModuleName) || InitialState;
	YH.register(HistoryModuleName, InitialState, RequestNewState);
	YH.onReady(ItemReady);

	YE.addListener(document, 'click', Document_Click);
	YE.addListener(document, 'keydown', keyDown);

	YE.addListener('mainImage', 'load', MainImageLoad);
	SetupButton('getHelp', '<help>');
	SetupButton('thumbsBtn', '<thumbs>');

	CalcLayout();

	try
	{
		YH.initialize("yui-history-field", "yui-history-iframe");
	} catch (e)
	{
		RequestNewState(InitialState);
	}
}

function keyDown(e)
{
	switch (e.keyCode)
	{
		case 37: // left arrow - previous image
			if (ImageNum > 0)
				Navigate(ImageNum - 1);
			YE.stopEvent(e);
			break;
		case 39: // right arrow - next image
			if (ImageNum < MediaCnt - 1)
				Navigate(ImageNum + 1);
			YE.stopEvent(e);
			break;
		case 40: // down arrow - previous page
			if (PageNum > 1 && !NoThumbs)
				Navigate((PageNum - 2) * ThumbsPerPage);
			YE.stopEvent(e);
			break;
		case 38: // up arrow - next page
			if (PageNum < NumPages && !NoThumbs)
				Navigate(PageNum * ThumbsPerPage);
			YE.stopEvent(e);
			break;
		case 73: // 'I' - Exif Info
			ToggleExifInfoPanel();
			YE.stopEvent(e);
			break;
		case 80: // 'P' - select page
			if (NumPages > 2)
				TogglePagePicker();
			YE.stopEvent(e);
			break;
		case 84: // 'T' - toggle thumbnail view
			ToggleThumbs();
			YE.stopEvent(e);
			break;
		case 219: // '[' - first image
			Navigate(0);
			YE.stopEvent(e);
			break;
		case 221: // ']' - last image
			Navigate(MediaCnt - 1);
			YE.stopEvent(e);
			break;
		case 13:
			window.open('http://www.forestmoon.com/Photos/' + MediaFileName(ImageNum), '_blank');
			YE.stopEvent(e);
			break;
	}
}

function encodeSpace(url)
{
	while (url.indexOf(' ') != -1)
		url = url.replace(' ', '%2520');
	return url;
}

function Document_Click(e)
{
	var el = YE.getTarget(e);
	if (el.MyLink != null)
	{
		if (typeof (el.MyLink) == 'string')
		{
			if (el.MyLink == '<page>')
				TogglePagePicker();
			else if (el.MyLink == '<info>')
				ToggleExifInfoPanel();
			else if (el.MyLink == '<help>')
				window.open('Help.htm', '_blank');
			else if (el.MyLink == '<thumbs>')
				ToggleThumbs();
		//	else if (el.MyLink == '<home>')
		//		window.navigate('http://www.ForestMoon.com/');	// why does this NOT work in Firefox?!
			else if (el.MyLink == '<show>')
				ToggleSlideshow();
			else if (el.MyLink == '<google>')
			{
				// http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=http:%2F%2Fwww.forestmoon.com%2FPhotos%2FFamily%2520Events%2FWinter%2F_gallery%2FWinter.kml&ie=UTF8
				var splitPath = GalleryPath.split(pathSep);
				var path = "";
				for (var i = 1; i < splitPath.length; ++i)
				{
					path = path + '%2F' + encodeSpace(splitPath[i]);
				}
				path = path + '%2F' + "_gallery";
				path = path + '%2F' + encodeSpace(splitPath[splitPath.length - 1]);
				path = 'http:%2F%2Fwww.forestmoon.com%2FPhotos' + path + '.kml';
				path = 'http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=' + path;
				//window.open(path + '&ie=UTF8&t=h&z=16', '_blank');
				window.open(path + '&ie=UTF8&t=h', '_blank');
			}
			else
				YH.navigate(HistoryModuleName, el.MyLink);
		}
		else
		{
			Navigate(el.MyLink);
		}
	}
}

function ShowExifInfoPanel()
{
	if (ExifInfoPanelHiding)
		return;
	var newPath = MediaFileName(ImageNum);

	if (newPath != ExifInfoPath)
	{
		// fetch the Exif data from the server
		WaitingExifInfo = true;
		ExifInfoPanelBuilt = false;
		ExifInfoPath = newPath;
		YAHOO.util.Connect.setDefaultPostHeader(false);
		YAHOO.util.Connect.initHeader("Content-Type", "application/json; charset=utf-8", true);
		var req = { "RelPath": newPath };
		var s = YAHOO.lang.JSON.stringify(req);
		YAHOO.util.Connect.asyncRequest('POST', 'WebService.asmx/GetPhotoInfo', InfoCallbacks, s);
		return;
	}

	if (!ExifInfoPanelBuilt)
	{
		var ib = YD.get('infoBody');
		while (ib.hasChildNodes())
		{
			ib.removeChild(ib.childNodes[0]);
		}
		var tr;
		tr = document.createElement('tr');
		ib.appendChild(tr);
		var td = document.createElement('td');
		YD.addClass(td, 'infoHdr');
		td.colSpan = 2;
		td.innerHTML = Gallery.MediaItems[ImageNum].FileName;
		tr.appendChild(td);
		for (var item in ExifInfo)
		{
			if (item.charAt(0) == '_')	// skip JSON meta data like '__type'
				continue;
			if (ExifInfo[item] == null)
				continue;
			tr = document.createElement('tr');
			ib.appendChild(tr);
			var td = document.createElement('td');
			YD.addClass(td, 'infoLabel');
			var re = /_/g;
			td.innerHTML = item.replace(re, " ");
			tr.appendChild(td);
			td = document.createElement('td');
			YD.addClass(td, 'infoData');
			if (item.indexOf('Link') != -1)
			{
				var anchor = document.createElement('a');
				anchor.setAttribute('href', ExifInfo[item]);
				anchor.setAttribute('target', '_blank');
				anchor.innerHTML = 'click here';
				td.appendChild(anchor);
			}
			else
			{
				td.innerHTML = ExifInfo[item];
			}
			tr.appendChild(td);
		}
		ExifInfoPanelBuilt = true;
	}

	if (ExifInfoPanel == undefined)
	{
		ExifInfoPanel = new YAHOO.widget.Panel("photoInfo", {
			width: "400px",
			visible: false,
			draggable: false,	// we'll do simple drag/drop on the whole panel ourselves
			close: false,
			underlay: 'none'
		});

		var r = ExifInfoPanel.render();
		// set up drag/drop on the whole panel
		YD.setStyle(ExifInfoPanel.element.id, 'cursor', 'move');
		ExifInfoPanel.dd2 = new YAHOO.util.DD(ExifInfoPanel.element.id, ExifInfoPanel.id, { dragOnly: true });
		ExifInfoPanel.dd2.scroll = false;
	}

	if (ExifInfoPanelShown)
		return;

	ExifInfoPanel.show();
	ExifInfoPanelShown = true;

	if (ExifInfoPanelPos == null)
	{
		ExifInfoPanelPos = YD.getXY('viewer');
	}
	else
	{
		// constrain the panel to reappearing in the viewport
		var size = getTrueSize(ExifInfoPanel.element);
		var vw = YD.getViewportWidth();
		var vh = YD.getViewportHeight();
		if (ExifInfoPanelPos[0] + size.width > vw)
			ExifInfoPanelPos[0] = vw - size.width;
		if (ExifInfoPanelPos[1] + size.height > vh)
			ExifInfoPanelPos[1] = vh - size.height;
	}
	var attributes = {
		points: { from: [0, -200], to: ExifInfoPanelPos }
	};
	var anim = new YAHOO.util.Motion(ExifInfoPanel.element, attributes, 0.75, YAHOO.util.Easing.backOut);
	anim.animate();
}

function CloseExifInfoPanel(animate)
{
	if (ExifInfoPanel == undefined)
		return;
	WaitingExifInfo = false;
	if (!ExifInfoPanelShown)
		return;
	if (!animate)
	{
		var pos = YD.getXY(ExifInfoPanel.element);
		if (pos[1] > 0)
			ExifInfoPanelPos = pos;
		ExifInfoPanel.hide();
		ExifInfoPanelShown = false;
		ExifInfoPanelHiding = false;
		return;
	}
	if (ExifInfoPanelHiding)
		return;
	ExifInfoPanelHiding = true;
	var pos = YD.getXY('Viewer');
	var attributes = {
		points: { to: [0, -200] }
	};
	ExifInfoPanelPos = YD.getXY(ExifInfoPanel.element);
	var anim = new YAHOO.util.Motion(ExifInfoPanel.element, attributes, 0.75, YAHOO.util.Easing.backIn);
	anim.onComplete.subscribe(function() { CloseExifInfoPanel(false); });
	anim.animate();
}

function ToggleExifInfoPanel()
{
	if (ExifInfoPanelShown)
		CloseExifInfoPanel(true);
	else
		ShowExifInfoPanel();
}

function SliderChange(offsetFromStart)
{
	// 10 pixels per second
	var secs = Math.round(delaySlider.getValue() / 10 + 1);
	YD.get('delay').innerHTML = secs;
	// interval in ms
	SlideShowInterval = secs * 1000;
	if (SlideShowTimerID != -1)
	{
		clearTimeout(SlideShowTimerID);
		SlideShowTimerID = setTimeout(SlideShowStep, SlideShowInterval);
	}
}

function ShowDelaySelector()
{
	if (delaySelectorShown)
		return;

	if (delaySelector == undefined)
	{
		delaySlider = YAHOO.widget.Slider.getHorizSlider("slider-bg",
                         "slider-thumb", 0, 290, 10);

		delaySlider.subscribe("change", SliderChange);

		delaySelector = new YAHOO.widget.Panel("delaySelector", {
			width: "344px",
			visible: false,
			draggable: false, // we'll do simple drag/drop on the whole panel ourselves
			close: false,
			underlay: 'none'
		});

		var r = delaySelector.render();
		// set up drag/drop on the whole panel
		YD.setStyle(delaySelector.element.id, 'cursor', 'move');
		delaySelector.dd2 = new YAHOO.util.DD(delaySelector.element.id, delaySelector.id, { dragOnly: true });
		delaySelector.dd2.scroll = false;
	}
	delaySelector.show();
	delaySelectorShown = true;
	// interval in ms, but 10 pixels per sec
	delaySlider.setValue(SlideShowInterval / 100 - 10, true); //false here means to animate if possible

	if (delaySelectorPos == null)
	{
		delaySelectorPos = YD.getXY('viewer');
	}
	else
	{
		// constrain the panel to reappearing in the viewport
		var size = getTrueSize(delaySelector.element);
		var vw = YD.getViewportWidth();
		var vh = YD.getViewportHeight();
		if (delaySelectorPos[0] + size.width > vw)
			delaySelectorPos[0] = vw - size.width;
		if (delaySelectorPos[1] + size.height > vh)
			delaySelectorPos[1] = vh - size.height;
	}

	var attributes = {
		points: { from: [0, -100], to: delaySelectorPos }
	};
	var anim = new YAHOO.util.Motion(delaySelector.element, attributes, 0.75, YAHOO.util.Easing.backOut);
	anim.animate();
}

function CloseDelaySelector(animate)
{
	if (delaySelector == undefined)
		return;
	if (!delaySelectorShown)
		return;
	if (!animate)
	{
		var pos = YD.getXY(delaySelector.element);
		if (pos[1] > 0)
			delaySelectorPos = pos;
		delaySelector.hide();
		delaySelectorShown = false;
		return;
	}
	var pos = YD.getXY('Viewer');
	var attributes = {
		points: { to: [0, -100] }
	};
	delaySelectorPos = YD.getXY(delaySelector.element);
	var anim = new YAHOO.util.Motion(delaySelector.element, attributes, 0.75, YAHOO.util.Easing.backIn);
	anim.onComplete.subscribe(function() { CloseDelaySelector(false); });
	anim.animate();
}

function ClearSlideShowTimerID()
{
	if (SlideShowTimerID != -1)
	{
		clearTimeout(SlideShowTimerID);
		SlideShowTimerID = -1;
	}
}

function MainImageLoad()
{
	if (SlideShowRunning)
	{
		ClearSlideShowTimerID();
		YD.get('statusImage').setAttribute('src', 'Images/busyspacer.gif');
		SlideShowTimerID = setTimeout(SlideShowStep, SlideShowInterval);
	}
}

function StartSlideShow()
{
	if (!SlideShowRunning && MediaCnt > 1)
	{
		SlideShowRunning = true;
		ShowDelaySelector();
		SlideShowStep();
	}
}

function StopSlideShow(animate)
{
	if (SlideShowRunning)
	{
		CloseDelaySelector(animate);
		ClearSlideShowTimerID();
		YD.get('statusImage').setAttribute('src', 'Images/busyspacer.gif');
		SlideShowRunning = false;
	}
}

function ToggleSlideshow()
{
	if (SlideShowRunning)
		StopSlideShow(true);
	else
		StartSlideShow();
}

function SlideShowStep()
{
	ClearSlideShowTimerID();
	var inx = ImageNum + 1;
	if (inx >= MediaCnt)
		inx = 0;
	// set a timer just in case we fail to get the image load event
//	SlideShowTimerID = setTimeout(MainImageLoad, 30000);
	Navigate(inx);
	YD.get('statusImage').setAttribute('src', 'Images/busy.gif');
}

function ShowGalPicker(path)
{
	if (galPickerShown)
		return;

	var folder = FindFolder(Folders, path);
	if (folder == null || folder.Folders == undefined || folder.Folders == null)
		return;
	var tr = YD.get('galRow');
	while (tr.hasChildNodes())
	{
		tr.removeChild(tr.childNodes[0]);
	}
	for (var i = 0; i < folder.Folders.length; ++i)
	{
		var td = document.createElement('td');
		YD.addClass(td, 'item');
		tr.appendChild(td);
		var img = document.createElement('img');
		var src = "ImageGen.ashx?path=" + folder.Folders[i].BasePath + "/_gallery/gallery.jpg&w=200&h=100&o=c";
		if (folder.Folders[i].Folders != null)
			src += "&i=FLD";
		img.setAttribute('src', src);
		SetupButton(img, path + pathSep + folder.Folders[i].Name);
		td.appendChild(img);
		var div = document.createElement('div');
		YD.addClass(div, 'title');
		div.innerHTML = folder.Folders[i].Name;
		td.appendChild(div);
	}

	var sep = path.lastIndexOf(pathSep);
	SetupButton('galUp', sep > 0 ? path.substr(0, sep) : null);

	var vw = YD.getViewportWidth();
	var cnt = Math.floor((vw - 40) / 212);
	if (cnt > folder.Folders.length)
		cnt = folder.Folders.length;
	else if (cnt < 1)
		cnt = 1;

	if (galPicker == undefined)
	{
		galPicker = new YAHOO.widget.Panel("galPicker", {
			width: '252px',
			visible: false,
			draggable: false,
			close: false,
			underlay: 'none'
		});

		var r = galPicker.render();
	}
	galPicker.cfg.setProperty('width', cnt * 212 + 40 + 'px');
	FilmStripInit('galPicker', cnt * 212);
	galPicker.show();
	galPickerShown = true;

	var pos = YD.getXY('viewer');
	var attributes = {
		points: { from: [0, -200], to: pos }
	};
	var anim = new YAHOO.util.Motion(galPicker.element, attributes, 0.75, YAHOO.util.Easing.backOut);
	anim.animate();
}

function CloseGalPicker(animate)
{
	if (galPicker == undefined)
		return;
	if (!galPickerShown)
		return;
	if (!animate)
	{
		galPicker.hide();
		galPickerShown = false;
		return;
	}
	var pos = YD.getXY('Viewer');
	var attributes = {
		points: { to: [0, -200] }
	};
	var anim = new YAHOO.util.Motion(galPicker.element, attributes, 0.75, YAHOO.util.Easing.backIn);
	anim.onComplete.subscribe(function() { CloseGalPicker(false); });
	anim.animate();
}

function ShowPagePicker()
{
	if (pagePickerShown)
		return;

	var pl = YD.get('pageList');
	while (pl.hasChildNodes())
	{
		pl.removeChild(pl.childNodes[0]);
	}
	var tr;
	for (var i = 1; i <= NumPages; ++i)
	{
		if ((i % 10) == 1)
		{
			tr = document.createElement('tr');
			pl.appendChild(tr);
		}
		var td = document.createElement('td');
		YD.addClass(td, 'pageNum');
		if (i == PageNum)
			YD.setStyle(td, 'color', 'Silver');
		SetupButton(td, (i - 1) * ThumbsPerPage);
		td.innerHTML = i;
		tr.appendChild(td);
	}

	if (pagePicker == undefined)
	{
		pagePicker = new YAHOO.widget.Panel("pagePicker", {
			width: "20em",
			visible: false,
			draggable: false,
			close: false,
			underlay: 'none'
		});

		var r = pagePicker.render();
	}
	pagePicker.show();
	pagePickerShown = true;

	var pos = YD.getXY('viewer');
	var attributes = {
		points: { from: [0, -100], to: pos }
	};
	var anim = new YAHOO.util.Motion(pagePicker.element, attributes, 0.75, YAHOO.util.Easing.backOut);
	anim.animate();
}

function ClosePagePicker(animate)
{
	if (pagePicker == undefined)
		return;
	if (!pagePickerShown)
		return;
	if (!animate)
	{
		pagePicker.hide();
		pagePickerShown = false;
		return;
	}
	var pos = YD.getXY('Viewer');
	var attributes = {
		points: { to: [0, -100] }
	};
	var anim = new YAHOO.util.Motion(pagePicker.element, attributes, 0.75, YAHOO.util.Easing.backIn);
	anim.onComplete.subscribe(function() { ClosePagePicker(false); });
	anim.animate();
}

function TogglePagePicker()
{
	if (pagePickerShown)
		ClosePagePicker(true);
	else
		ShowPagePicker();
}

function DumpElement(el)
{
//	var s = "";
	if (typeof (el) === 'string')
		el = YD.get(el);
	alert(el.innerHTML);
//	s += "<" + el.nodeName + ">" + el.id + "\r\n";
//	s += '"' + el.innerHTML + '"';
//	if (!confirm(s))
//		return false;
//	var child = YD.getFirstChild(el);
//	while (child != null)
//	{
//		if (!DumpElement(child))
//			return false;
//		child = YD.getNextSibling(child);
//	}
//	return true;
}

function DumpObjectProperties(obj)
{
	var s = "";
	var p;
	for (p in obj)
		s = s + " " + p;
	return s;
}

function GetExtension(filename)
{
	var dot = filename.lastIndexOf('.');
	return filename.substr(dot + 1).toUpperCase();
}

function SetImgSrc(img, inx, size)
{
	if (inx < 0)
	{
		YD.get(img).setAttribute('src', 'Images/placeholder.gif');
		return;
	}
	var src = "ImageGen.ashx?path=" + escape(MediaFrameName(inx));
	src += '&w=' + ImageWidths[size];
	src += '&h=' + ImageHeights[size];
	if (size == 0)
	{
		src += '&o=p';
	}
	var icon = MediaFileName(inx);
	if (icon != MediaFrameName(inx))
	{
		icon = GetExtension(icon);
		src += '&i=' + icon;
	}
	if (YD.get(img).getAttribute('src') == src)
	{
		return;
	}
	YD.get(img).setAttribute('src', src);
}

function Image_Mouseover(e)
{
	var el = YE.getTarget(e);
	if (el.nodeName.toUpperCase() == "IMG")
		swapImgBorder(el, 'over');
}

function Image_Mouseout(e)
{
	var el = YE.getTarget(e);
	if (el.nodeName.toUpperCase() == "IMG")
		swapImgBorder(el, 'out');
}

function Image_Load(e)
{
	var el = YE.getTarget(e);
	YE.removeListener(el, 'load', Image_Load);
}

function ArrangeThumbs()
{
	// remove all thumbnails
	var tbody = YD.get('thumbsList');
	YE.purgeElement(tbody, true);
	while (tbody.hasChildNodes())
	{
		tbody.removeChild(tbody.childNodes[0]);
	}

	var el = YD.get('pageNav');
	YD.setStyle(el, 'visibility', !NoThumbs ? 'inherit' : 'hidden');
//	YD.setStyle(el, 'display', NoThumbs ? 'none' : '');
	if (NoThumbs)
		return;
	
	// determine range of thumbnail indices on the page
	var position = ((PageNum - 1) * ThumbsPerPage);
	var stopPosition = position + ThumbsPerPage;
	if (stopPosition > MediaCnt)
		stopPosition = MediaCnt;

	var i = 0;
	
	// create all new thumbnails
	var row;
	while (position >=0 && position < stopPosition)
	{
		if (i % ThumbsPerRow == 0)
		{
			// create new row
			row = document.createElement('tr');
			YD.addClass(row, 'thumbsTR');
			tbody.appendChild(row);
		}
		
		// create cell
		var cell = document.createElement('td');
		YD.addClass(cell, 'thumbTD');
		row.appendChild(cell);

		// create the IMG
		var img = document.createElement('img');
		YD.addClass(img, 'thumbImg');
		YD.addClass(img, 'imgBorder');
		var title = Gallery.MediaItems[position].Title || "";
		img.setAttribute('alt', title);
		img.setAttribute('title', title);
		YD.setStyle(img, 'width', ImageWidths[0] + 'px');
		YD.setStyle(img, 'height', ImageHeights[0] + 'px');
		SetImgSrc(img, position, 0);
		SetupButton(img, position);
		cell.appendChild(img);

		i++;
		position++;
	}
}

function swapImgBorder(img, state)
{
	if (state === "over")
	{
		YD.replaceClass(img, 'imgBorder', 'imgBorderOn');
	}
	else if (state === "out")
	{
		YD.replaceClass(img, 'imgBorderOn', 'imgBorder');
	}
}

function getTrueSize(el)
{
	if (typeof (el) === 'string')
		el = YD.get(el);
	var size = { width: 0, height: 0 };
	var m = parseInt(YD.getStyle(el, 'marginLeft'), 10);
	if (!isNaN(m))
	{
		size.width += m;
	}
	m = parseInt(YD.getStyle(el, 'marginRight'), 10);
	if (!isNaN(m))
	{
		size.width += m;
	}
	m = parseInt(YD.getStyle(el, 'marginTop'), 10);
	if (!isNaN(m))
	{
		size.height += m;
	}
	m = parseInt(YD.getStyle(el, 'marginBottom'), 10);
	if (!isNaN(m))
	{
		size.height += m;
	}
	size.width += el.offsetWidth;
	size.height += el.offsetHeight;
	return size;
}

function getSizes()
{
	// clientWidth - Retrieves the width of the object including padding,
	//		but not including margin, border, or scroll bar.

	var trueSize = getTrueSize('thumbSample');
	ThumbWidthExtra = trueSize.width - 100; 	// sample uses 100x100 size
	ThumbHeightExtra = trueSize.height - 100;	// remove that to get extra
	trueSize = getTrueSize('mainImage');
	MainImgWidthExtra = trueSize.width - 100;
	MainImgHeightExtra = trueSize.height - 100;
	ViewerPadding = findPadding('viewer');
	HeaderHeight = YD.getY('viewer');
	FooterHeight = getTrueSize('captions').height;
}

function findPadding(el)
{
	if (typeof (el) === 'string')
		el = YD.get(el);
	var pad = 0;
	var v = parseInt(YD.getStyle(el, 'paddingLeft'), 10);
	if (!isNaN(v))
		pad += v;
	v = parseInt(YD.getStyle(el, 'paddingRight'), 10);
	if (!isNaN(v))
		pad += v;
	return pad;
}

function ToggleThumbs()
{
	NoThumbs = !NoThumbs;
	CalcLayout();
}

function CalcLayout()
{
	// see how much width we have to work with
	var ViewerDivWidth = YD.getViewportWidth() - ViewerPadding - MainImgWidthExtra;
	var ThumbWidth = ImageWidths[0] + ThumbWidthExtra;
	var ThumbHeight = ImageHeights[0] + ThumbHeightExtra;
	var maxMainWidth = ViewerDivWidth;

	if (!NoThumbs)
		maxMainWidth -= (ThumbWidth * DesiredThumbsPerRow);

	// determine optimal image size based on available width
	var newMainImageSize = 1;
	for (var i = 1; i < ImageWidths.length; ++i)
	{
		if (maxMainWidth <= ImageWidths[i])
			break;
		newMainImageSize = i;
	}

	// constrain the image size based on available height
	var maxMainHeight = YD.getViewportHeight() - HeaderHeight - FooterHeight - MainImgHeightExtra;
	var vertSize = 1;
	for (i = 1; i < ImageHeights.length; ++i)
	{
		if (maxMainHeight <= ImageHeights[i])
			break;
		vertSize = i;
	}
	if (vertSize < newMainImageSize)
		newMainImageSize = vertSize;

	// calc new thumbnail grid dimensions
	var newThumbsPerColumn = 0;
	var newThumbsPerRow = 0;
	if (!NoThumbs)
	{
		newThumbsPerColumn = Math.floor((ImageHeights[newMainImageSize] + MainImgHeightExtra) / ThumbHeight);
		newThumbsPerRow = Math.floor((ViewerDivWidth - ImageWidths[newMainImageSize]) / ThumbWidth);
		if (newThumbsPerRow < MinThumbsPerRow)
			newThumbsPerRow = MinThumbsPerRow;
	}
	
	// set thumbnails width
	if (ThumbsPerRow != newThumbsPerRow)
	{
		ThumbsPerRow = newThumbsPerRow;
	//	var w = ThumbsPerRow * ThumbWidth;
	//	var t = YD.get('thumbnails');
	//	YD.setStyle(t, 'width', w + "px");
	}

	// check for change in main image size
	if (MainImageSize != newMainImageSize)
	{
		MainImageSize = newMainImageSize;
		YD.setStyle('main', 'width', ImageWidths[MainImageSize] + 9 + "px");
		YD.setStyle('main', 'height', ImageHeights[MainImageSize] + 9 + "px");
		SetMainImageSrc();
	}

	// check for change in number of thumbnails
	var newThumbsPerPage = newThumbsPerRow * newThumbsPerColumn;
	var newNumPages = (NoThumbs) ? 0 : Math.ceil(MediaCnt / newThumbsPerPage);
	if (ThumbsPerPage != newThumbsPerPage || newNumPages != NumPages)
	{
		ThumbsPerPage = newThumbsPerPage;
		NumPages = newNumPages;
		SetupButton('pageSel', NumPages > 2 ? '<page>' : null);
		SetupButton('google', (Gallery != null && Gallery.HasKmlFile != null && Gallery.HasKmlFile == 'True') ? '<google>' : null);

		ClosePagePicker(false);

		if (NoThumbs)
			PageNum = -1;
		else if (ImageNum < 0)
			PageNum = 0;
		else
			PageNum = Math.floor(ImageNum / ThumbsPerPage) + 1;
		SetNav();
		ArrangeThumbs();
	}
}

function SetMainImageSrc()
{
	SetImgSrc('mainImage', ImageNum, MainImageSize);
}

function EnableButton(el, en)
{
	// opacity looked cool but was causing visibility issues
	// in the galPicker with the right button for some reason
	// and it kills performance, especially for animation
//	YD.setStyle(el, 'opacity', en ? 1 : 0.4);
	YD.setStyle(el, 'visibility', en ? 'inherit' : 'hidden');
	YD.setStyle(el, 'cursor', en ? 'pointer' : 'inherit');
}

function SetupButton(el, link)
{
	if (typeof (el) === 'string')
		el = YD.get(el);
	EnableButton(el, link != null);
	el.MyLink = link;
}

function SetNavSection(inx, cnt, inc, label)
{
	if (inx < 0)
	{
		return;
	}
	SetupButton('prev' + label, inx > 1 ? (inx - 2) * inc : null);
	YD.get(label + 'Num').innerHTML = inx;
	YD.get(label + 'Cnt').innerHTML = cnt;
	SetupButton('next' + label, inx < cnt ? inx * inc : null);
}

function SetNav()
{
	// set page navigation
	SetNavSection(PageNum, NumPages, ThumbsPerPage, 'Page');
	
	// set item navigation
	SetNavSection(ImageNum + 1, MediaCnt, 1, 'Item');
}

function FindImageByName(name)
{
	for (var i = 0; i < MediaCnt; ++i)
	{
		if (MediaItemName(i) == name)
		{
			return i;
		}
	}
	return -1;
}

function SetMainImageNum(inx)
{
	if (inx == ImageNum || inx < 0)
	{
		ImageNum = inx;
		SetMainImageSrc();
		if (inx < 0)
		{
			SetupButton('getInfo', null);
			CloseExifInfoPanel(false);
			SetupButton('slideShow', null);
			StopSlideShow(false);
			YD.get('credit').innerHTML = "&copy;&nbsp;Scott Ferguson";
			YD.get('desc').innerHTML = "Gallery viewer for Forest Moon Productions";
			YD.setStyle('mainImage', 'width', '');
			YD.setStyle('mainImage', 'height', '');
		}
		return;
	}
	ImageNum = inx;
	SetupButton('getInfo', '<info>');
	SetupButton('slideShow', MediaCnt > 1 ? '<show>' : null);
	if (ExifInfoPanelShown && !ExifInfoPanelHiding)
		ShowExifInfoPanel(); // refresh panel with new image data

	// set the Title text
	YD.get('title').innerHTML = Gallery.MediaItems[ImageNum].Title || "";

	// set the Credit text
	YD.get('credit').innerHTML = "&copy;&nbsp;" + (Gallery.MediaItems[ImageNum].Credit || Gallery.Credit);

	// set the Body text
	YD.get('desc').innerHTML = Gallery.MediaItems[ImageNum].Body || "";

	// get the ANCHOR
	var anchor = YD.get('mainImageLink');
	anchor.setAttribute('href', 'http://www.forestmoon.com/Photos/' + MediaFileName(ImageNum));

	// get the IMG
	var displayImage = YD.get('mainImage');
	YD.setStyle(displayImage, 'width', '');
	YD.setStyle(displayImage, 'height', '');
	displayImage.setAttribute('alt', Gallery.MediaItems[ImageNum].Title || "");

	if (MediaFileName(ImageNum) != MediaFrameName(ImageNum))
		displayImage.setAttribute('title', 'click to view ' + GetExtension(MediaFileName(ImageNum)) + ' file');
	else
		displayImage.setAttribute('title', 'click to view full-sized media');

	SetMainImageSrc();
	var oldPageNum = PageNum;
	if (ImageNum < 0)
		PageNum = 0;
	else
		PageNum = Math.floor(ImageNum / ThumbsPerPage) + 1;
	SetNav();
	if (oldPageNum != PageNum)
		ArrangeThumbs();
}

var FilmStripSleeve;
var FilmStripLeftBtn;
var FilmStripRightBtn;
var FilmStripFirstBtn;
var FilmStripLasttBtn;
var FilmStripScrollMax;

function FilmStripInit(el, w)
{
	var fs = YD.get(el);
	var strip = YD.getElementsByClassName('strip', null, fs)[0];
	if (FilmStripSleeve == null)
	{
		FilmStripSleeve = YD.getElementsByClassName('sleeve', null, fs)[0];
		FilmStripLeftBtn = YD.getElementsByClassName('navLeft', null, fs)[0];
		FilmStripRightBtn = YD.getElementsByClassName('navRight', null, fs)[0];
		FilmStripFirstBtn = YD.getElementsByClassName('navFirst', null, fs)[0];
		FilmStripLastBtn = YD.getElementsByClassName('navLast', null, fs)[0];
		YE.on(FilmStripLeftBtn, 'click', FilmStripDoLeft);
		YE.on(FilmStripRightBtn, 'click', FilmStripDoRight);
		YE.on(FilmStripFirstBtn, 'click', FilmStripDoFirst);
		YE.on(FilmStripLastBtn, 'click', FilmStripDoLast);
	}
	YD.setStyle(FilmStripSleeve, 'width', w + 'px');
	FilmStripSleeve.scrollLeft = 0;
	FilmStripScrollMax = strip.offsetWidth - FilmStripSleeve.offsetWidth;
	if (FilmStripScrollMax < 0)
		FilmStripScrollMax = 0;
	FilmStripUpdateElements();
}

function FilmStripUpdateElements()
{
	EnableButton(FilmStripLeftBtn, FilmStripSleeve.scrollLeft > 0);
	EnableButton(FilmStripRightBtn, FilmStripSleeve.scrollLeft < FilmStripScrollMax);
	EnableButton(FilmStripFirstBtn, FilmStripSleeve.scrollLeft > FilmStripSleeve.offsetWidth);
	EnableButton(FilmStripLastBtn, FilmStripSleeve.scrollLeft < FilmStripScrollMax - FilmStripSleeve.offsetWidth);
}

function FilmStripAnimate(v)
{
	var anim = new YAHOO.util.Scroll(FilmStripSleeve, { scroll: { to: [v, 0]} }, 0.5, YAHOO.util.Easing.easeOut);
	anim.onComplete.subscribe(FilmStripUpdateElements);
	anim.animate();
};

function FilmStripDoLeft()
{
	var v = FilmStripSleeve.scrollLeft - FilmStripSleeve.offsetWidth;
	if (v < 0)
		v = 0;
	FilmStripAnimate(v);
};

function FilmStripDoRight()
{
	var v = FilmStripSleeve.scrollLeft + FilmStripSleeve.offsetWidth;
	if (v > FilmStripScrollMax)
		v = FilmStripScrollMax;
	FilmStripAnimate(v);
};

function FilmStripDoFirst()
{
	FilmStripAnimate(0);
};

function FilmStripDoLast()
{
	FilmStripAnimate(FilmStripScrollMax);
};
