/* ****************************************************************************
**
* FILE: 	photoshow.js
* PRODUCT:	website
* AUTHOR: 	Ingo Karkat <ingo@karkat.de>
* DATE CREATED:	15-Mar-2009
*
*******************************************************************************
* CONTENTS: 
    Adds a photo show to a photo album page. It is assumed that all photos are
    contained in separate tables (optionally with table captions) on the photo
    page. There can be a link to the next photo page; this link must be placed
    after all photos. 

* USAGE:
    Include jQuery and this script in the page head. 
    To configure a link to for the "end of photo show" button, include this in
    the page head: 
	<link id=photoshowend" href="path/to/endpage.html">

* DEPENDENCIES: 
    - jQuery 1.3 or later

* REMARKS: 

* Copyright: (C) 2009 by Ingo Karkat
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License.
    See http://www.gnu.org/copyleft/gpl.txt 

* REVISION	DATE		REMARKS 
	006	06-Jun-2009	Now determining the base path for including
				widget images from this script's URL. This
				allows pages located anywhere to use this
				script. 
				Factored out UI element creation into
				makeWidget(). 
				Link for the "end of photo show" button is now
				configured via link tag. 
	005	24-May-2009	Moved photo pages into 'yearN' subdirectories. 
	004	07-Apr-2009	BF: Photoshow icons now have CSS class 'create
				pagemargin', because the latest stylesheet
				didn't automatically reserve the margin space
				any more. 
	003	20-Mar-2009	Now also handling page without any photos:
				Either "end show" or "next page" icon is shown. 
				Factored out functionality into a photoshow
				object. 
				Factored out UI elements into separate object. 
	002	16-Mar-2009	Now supporting linking to (dynamically added)
				photo anchors. 
				Implemented continuation of show on next page. 
				Photo starter is only added to first heading on
				the page. 
				Anchor now added as a separate element before
				the photo. 
				BF: The link to the next page may be in a parent
				element. 
	001	15-Mar-2009	file creation
******************************************************************************/

$(document).ready(function() {
    var photoshow = {
	basePath: function() {
	    var scriptPath;
	    $("script[src]").each(function() {
		var selfScriptMatch = this.src.match(/(^|^.*[\/\\])photoshow\.js(?:\?|$)/);
		if (selfScriptMatch) {
		    scriptPath = selfScriptMatch[1];
		    return true;
		}
	    });
	    return scriptPath;
	}(),
	ui: {
	    makeWidget: function(link, imageName, altName, title) {
		var widgetImage = $('<img>');
		widgetImage.attr('src', photoshow.basePath + imageName);
		widgetImage.attr('alt', altName);
		widgetImage.attr('title', title);
		widgetImage.attr('class', "create pagemargin");
		var widget = $('<a></a>');
		widget.attr('href', (link ? link : "#"));
		widget.html(widgetImage);
		return widget;
	    },
	    startPhoto: function() {
		return photoshow.ui.makeWidget("", "startphoto.png", "Start show", "Click to start photo show.");
	    },
	    nextPhoto : function() {
		return photoshow.ui.makeWidget("", "nextphoto.png", "next photo", "Click to go to next photo.");
	    },
	    nextPhotoPage : function() {
		return photoshow.ui.makeWidget("", "nextphotopage.png", "next page", "Click to continue on the next page.");
	    },
	    endPhoto : function() {
		return photoshow.ui.makeWidget($('link#photoshowend').attr('href'), "endphoto.png", "The end", "This is the end of the photo show. Click to go back to the start.");
	    }
	},
	addAnchors : function(results) {
	    results.each(function(i) {
		var anchor = i + 1;
		/* The anchor is not simply added as an id attribute to the
		 * photo table, but before it as a separate anchor element. This
		 * is done so that if the photo doesn't fit next to the jumper
		 * (which is left-floating) it cannot push the jumper off the
		 * page. This way, the jumper will be inserted before the photo
		 * but after the anchor, and will always be at the top of the
		 * window when jumped to. 
		 */
		$(this).before($('<a name="' + anchor + '"></a>'));
	    });
	},
	nextPageLink : function(element) {
	    /* The link to the next album page comes after the current photo,
	     * and is the last link on the page. We do not simply query for the
	     * last link, because that one may be an "enlarge" image link inside
	     * the last photo or even a totally different link before the last
	     * photo. (I don't whether it's possible to compare DOM elements
	     * according to their position.) 
	     */
	    var link = $(element).nextAll().children().filter('a:last');
	    if (link.length > 0) {
		return link;
	    } else {
		/* The last photo may be in a nested structure, and the
		 * next-page link not. So try searching in elements following
		 * the parent, too, until the top content level is reached. 
		 */
		var parent = $(element).parent(':not(body)');
		if (parent.length > 0) {
		    return photoshow.nextPageLink(parent);
		} else {
		    return [];
		}
	    }
	},
	jumperToNextPage : function(element) {
	    var nextPageLink = photoshow.nextPageLink(element);
	    var jumper;
	    if (nextPageLink.length > 0) {
		jumper = photoshow.ui.nextPhotoPage();
		jumper.attr('href', nextPageLink.attr('href') + "#photoshow");
	    } else {
		jumper = photoshow.ui.endPhoto();
	    }
	    return jumper;
	},
	jumperToAnchor : function(anchorName) {
	    var jumper = photoshow.ui.nextPhoto();
	    jumper.attr('href', "#" + anchorName);
	    return jumper;
	}
    };

    var photos = $('table');
    photoshow.addAnchors(photos);

    var starter = photoshow.ui.startPhoto();
    starter.click(function() {
	starter.unbind("click");
	starter.attr('href', '#1');

	var lastPhotoIdx = photos.length - 1;
	if (lastPhotoIdx == -1) {
	    $(this).replaceWith(photoshow.jumperToNextPage());
	} else {
	    photos.each(function(i) {
		var nextAnchor = i + 2;
		var jumper = (i == lastPhotoIdx ?
		    photoshow.jumperToNextPage(this) :
		    photoshow.jumperToAnchor(nextAnchor)
		);
		$(this).before(jumper).after($('<br style="margin-bottom: 50%;">'));
	    });
	}

	starter.click();
    });

    // Install photo starter in first heading on the page. 
    var headings = $("h1,h2,h3,h4,h5,h6");
    if (headings.length > 0) {
	$(headings[0]).before(starter).after($('<br clear="all">'));
    }

    // Handle photo anchors. 
    if (/^#\d+$/.test(window.location.hash)) {
	/* The photo anchors didn't exist when the page was opened, so the
	 * browser didn't jump there. Now that the anchors have been set, make
	 * the browser jump there. 
	 */
	window.location.hash = window.location.hash;
    }

    // Handle continuation of photo show. 
    if (window.location.hash == "#photoshow") {
	/* If this page was opened with the "virtual" photoshow anchor, we
	 * enable the photoshow controls and jump right to the first photo. 
	 */
	starter.click();
	window.location.hash = "#1";
    }
});


