/*
 * Gallery - a web based photo album viewer and editor
 * Copyright (C) 2000-2007 Bharat Mediratta
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
 */

/* Global Variables */

var thumbnails;			/* array of thumbnails */
var currentImageIndex;		/* index into thumbnails array */
var mainPhoto;			/* The central image */
var photoScalingInterval;	/* scaling animation tracker */
var showLoadingTimeout;		/* Cancel the loading message display */
var showImageDataFadeTimeout	/* Fade in image data block */

var MAIN_PHOTO_WIDTH = 460;	/* Width each image is resized to when first loaded */
var PHOTO_MINIMISED = 300;	/* Width each image is resized down to when clicked */
var SCALE_DOWN_FACTOR = 12;	/* Pixels that an image scales down by at each step */
var SCALE_UP_FACTOR = 18;	/* Pixels that an image scales *up* by at each step */

/* @REVISIT: For preloading... */
fullsizePhotos = new Array();
fullsizeCount = 0;

/* Initialisation */
addEvent(window, 'load', init, false);

function init() {
    if (!document.getElementById) {
	/* Required functionality for even the most basic DHTML. */
	return;
    }
    /* Set up thumbnails */
    var thumbholder = document.getElementById('gsThumbMatrix');
    if (!thumbholder) {
	setupBackToAlbumLink(); /* Not an album page */
	return;
    }
    thumbnails = thumbholder.getElementsByTagName('img');
    for (var i = 0; i < thumbnails.length; i++) {
	thumbnails[i].thumbIndex = i;
	addEvent(thumbnails[i], 'click', activateThumbnail, false);
	thumbnails[i].onclick = cancelEventSafari;
    }

    /*
     * If the user has just come from a photo page, they may have a cookie set that holds the index
     * of the image that was active in the show when they left. Now they can rejoin at that point.
     */
    if (readCookie('slideshowOffset') != null &&
	    Number(readCookie('slideshowOffset')) < thumbnails.length) {
	currentImageIndex = Number(readCookie('slideshowOffset'));
	eraseCookie('slideshowOffset');
	addMessage('Restarting slideshow at index ' + currentImageIndex);
    } else {
	currentImageIndex = 0;
    }

    if (slideshowImages.length > 0) {
      setupMainImage();
      switchImages(currentImageIndex, true);
    }

    setupSubAlbums();
}

/* Called each time a new image is switched to */
function setupMainImage() {
    mainPhoto = document.getElementById('main-image');

    if (slideshowImageWidths[currentImageIndex] < 0
	    || MAIN_PHOTO_WIDTH <= slideshowImageWidths[currentImageIndex]) {
	mainPhoto.style.width = MAIN_PHOTO_WIDTH + 'px';
    } else {
	/*
	 * The image is below our ideal slideshow width, so we don't want to stretch it
	 * horizontally.  Instead we center the image that we have a little better.
	 */
	mainPhoto.style.width = slideshowImageWidths[currentImageIndex] + 'px';
	mainPhoto.style.left = parseInt(getElementStyle(mainPhoto.id, 'left')) +
	    ((MAIN_PHOTO_WIDTH - slideshowImageWidths[currentImageIndex])/2) + 'px';
    }
    mainPhoto.style.height = 'auto'; /* @REVISIT - Safari doesn't play nice with this */

    mainPhoto.origWidth = parseInt(getElementStyle(mainPhoto.id, 'width'));
    mainPhoto.origLeft = parseInt(getElementStyle(mainPhoto.id, 'left'));
    mainPhoto.galleryimg = 'no'; /* Disables IE's image toolbar, which was causing flicker */

    addEvent(mainPhoto, 'click', showPhotoDetails, false);
}

function activateThumbnail(e) {
    /* Find the source element through varying levels of browser support */
    var targetElement = window.event ? window.event.srcElement : e ? e.target : null;
    if (!targetElement) {
	return;
    }
    knackerEvent(e);
    switchImages(targetElement.thumbIndex);
    targetElement.blur();	/* Remove focus halo */
}

function switchImages(thumbIndex, firstLoad) {
    removeImageDataBlock();
    if (currentImageIndex == thumbIndex && !firstLoad) {
	addMessage("That image is already selected.");
	return;
    }
    /* Wrap around */
    if (thumbIndex < 0) {
	thumbIndex = thumbnails.length - 1;
    } else if (thumbIndex == thumbnails.length) {
	thumbIndex = 0;
    }
    if (slideshowImageWidths[thumbIndex] < 0) {
	/* This item is not a photo.. redirect to view it */
	if (!firstLoad) {
	    location = slideshowImages[thumbIndex];
	} else {
	    hideLoadingMessage();
	}
	return;
    }
    highlightCurrentThumb(thumbIndex);
    updateItemTitle(thumbIndex);

    hideLoadingMessage();

    var newImageSrc = slideshowImages[thumbIndex];
    var newImage = document.createElement('img');

    mainPhoto.id = null; /* Isn't enough in some browsers */
    mainPhoto.removeAttribute('id');

    newImage.id = 'main-image';
    addEvent(newImage, 'load', bigPhotoLoad, false);
    addEvent(newImage, 'error', bigPhotoFail, false);

    if (slideshowState == PLAYING) {
	pause();
	returnToPlaying = true;
    }

    /* Avoid showing loading message if its going to be fast */
    showLoadingTimeout = setTimeout("showLoadingMessage()", 600);

    addMessage("Swapping " + currentImageIndex + ", and " + thumbIndex + "...");
    currentImageIndex = thumbIndex;

    newImage.src = newImageSrc;
    mainPhoto.parentNode.removeChild(mainPhoto);
    document.getElementById('sliding-frame').getElementsByTagName('p')[0].appendChild(newImage);
    setupMainImage();

    if (mainPhoto.state == 'downsized') {
	insertimagedatablock();
    }
}

function bigPhotoLoad() {
    mainPhoto.style.height = 'auto';
    addMessage('Photo loaded');
    hideLoadingMessage();

    /*
     * The little switcheroo below prevents a problem with IE incorrectly calculating the 'height'
     * property for an image that has had its width changed when set to 'auto' (they should scale
     * together). Should be imperceptible in other browsers.
     */
    mainPhoto.style.height = '345px';
    mainPhoto.style.height = 'auto';
    if (returnToPlaying) {
	play();
    }
}

function bigPhotoFail() {
    addMessage('FAIL: Photo failed to load...');
    addMessage(mainPhoto.src);
    hideLoadingMessage();
    if (slideshowState == PLAYING) {
	advanceSlideShow();
    }
}

function showLoadingMessage() {
    var loadingMsg = document.createElement('div');
    loadingMsg.id = 'loading';
    loadingMsg.appendChild(document.createTextNode(LOADING_IMAGE));
    document.getElementById('main-image-container').appendChild(loadingMsg);
}

function hideLoadingMessage() {
    clearTimeout(showLoadingTimeout);
    var loading = document.getElementById('loading');
    if (loading && getElementStyle(loading.id, '-moz-opacity') > 0.0) {
	loading.style.MozOpacity = parseFloat(getElementStyle(loading.id, '-moz-opacity')) - 0.05;
	showLoadingTimeout = setTimeout("hideLoadingMessage()", 50);
    } else if (loading) {
	loading.parentNode.removeChild(loading);
    }
}

function highlightCurrentThumb(thumbIndex) {
    /* First, un-highlight the current image... */
    thumbnails[currentImageIndex].className =
	thumbnails[currentImageIndex].className.replace(/\bcurrentImage\b/, '');
    thumbnails[thumbIndex].className += ' currentImage';
}

function updateItemTitle(thumbIndex) {
    var itemTitle = document.getElementById('item-title').firstChild;
    itemTitle.data = thumbnails[thumbIndex].getAttribute('alt');
}

/*
 * Photo -scaling functions
 */
function showPhotoDetails(e) {
    addMessage('scaling image, dimensions: ' + mainPhoto.origWidth + 'x' + mainPhoto.origHeight);
    clearInterval(photoScalingInterval);
    if (slideshowState == PLAYING) {
	pause();
	returnToPlaying = true;
    }

    if (mainPhoto.state != 'downsized') {
	photoScalingInterval = setInterval("downSizePhoto()", 30);
	mainPhoto.state = 'downsized';
    } else {
	removeImageDataBlock();
	photoScalingInterval = setInterval("upSizePhoto()", 20);
	mainPhoto.state = 'upsized';
    }
}

function downSizePhoto() {
    if (parseInt(mainPhoto.style.width) > PHOTO_MINIMISED ||
	    parseInt(getElementStyle(mainPhoto.id, 'left')) > 40) {
	if (parseInt(mainPhoto.style.width) > PHOTO_MINIMISED) {
	    mainPhoto.style.width = parseInt(mainPhoto.style.width) - SCALE_DOWN_FACTOR + 'px';
	}

	/* REVISIT Works in everything but Safari... */
	mainPhoto.style.height = 'auto';

	if (parseInt(getElementStyle(mainPhoto.id, 'left')) > 40) {
	    mainPhoto.style.left = (parseInt(getElementStyle(mainPhoto.id, 'left')) -
		mainPhoto.origLeft/12) + 'px';
	}
	if (getElementStyle(mainPhoto.id, 'top') == 'auto') {
	    mainPhoto.style.top = '0';
	}
	if (parseInt(getElementStyle(mainPhoto.id, 'top')) < 40) {
	    mainPhoto.style.top = (parseInt(getElementStyle(mainPhoto.id, 'top')) + 5) + 'px';
	}
    } else {
	clearInterval(photoScalingInterval);
	addMessage('Image scaled to ' + mainPhoto.style.width + 'x' + mainPhoto.style.height);
	mainPhoto.state = 'downsized';
	insertimagedatablock();
    }
}

function upSizePhoto() {
    if (parseInt(mainPhoto.style.width) < mainPhoto.origWidth ||
	    parseInt(getElementStyle(mainPhoto.id, 'left')) < mainPhoto.origLeft) {
	if (parseInt(mainPhoto.style.width) < mainPhoto.origWidth-5) {
	    mainPhoto.style.width = (parseInt(mainPhoto.style.width) + SCALE_UP_FACTOR) + 'px';
	}
	if (parseInt(getElementStyle(mainPhoto.id, 'left')) < mainPhoto.origLeft) {
	    mainPhoto.style.left = (parseInt(getElementStyle(mainPhoto.id, 'left')) +
		mainPhoto.origLeft/10) + 'px';
	}
	if (parseInt(getElementStyle(mainPhoto.id, 'top')) > 0) {
	    mainPhoto.style.top = (parseInt(getElementStyle(mainPhoto.id, 'top')) - 5) + 'px';
	}
    } else {
	/* Clean up and reset */
	clearInterval(photoScalingInterval);
	mainPhoto.style.width = mainPhoto.origWidth + 'px';
	mainPhoto.style.height = 'auto';
	mainPhoto.style.left = mainPhoto.origLeft + 'px';
	mainPhoto.style.top = 'auto';
	addMessage('Image scaled back to ' + mainPhoto.width + 'x' + mainPhoto.height);
	mainPhoto.state = 'upsized';
	if (returnToPlaying) {
	    play();
	}
    }
}

function insertimagedatablock() {
    var dataBlock = document.createElement('div');
    dataBlock.id = 'imagedatablock';

    var dataBlockHeading = document.createElement('h3');
    dataBlockHeading.appendChild(document.createTextNode(PHOTO_DATA));
    dataBlock.appendChild(dataBlockHeading);

    if (thumbnails[currentImageIndex].className.match(/size:=([0-9]+)=/)) {
	var imageSize = Number(RegExp.$1) / 1024;
	var sizeInfo = document.createElement('p');
	sizeInfo.appendChild(
	    document.createTextNode(FILE_SIZE.replace(/%SIZE%/, Math.round(imageSize))));
	dataBlock.appendChild(sizeInfo);
    }
    if (thumbnails[currentImageIndex].className.match(/summary:=([^=]+)=/)) {
	var summaryInfo = document.createElement('p');
	summaryInfo.appendChild(document.createTextNode(SUMMARY + RegExp.$1));
	dataBlock.appendChild(summaryInfo);
    }
    if (thumbnails[currentImageIndex].className.match(/description:=(.+)=/)) {
	var descriptionInfo = document.createElement('p');
	descriptionInfo.appendChild(document.createTextNode(DESCRIPTION + RegExp.$1));
	dataBlock.appendChild(descriptionInfo);
    }

    var fullsizeLink = document.createElement('a');
    fullsizeLink.id = 'fullsizelink';
    fullsizeLink.href = thumbnails[currentImageIndex].parentNode.href
	+ (thumbnails[currentImageIndex].parentNode.href.indexOf('?') >= 0 ? '&' : '?')
	+ 'thumbIndex=' + currentImageIndex;
    /* Allow a user to rejoin the slideshow at this point */
    addEvent(fullsizeLink, 'click', saveCurrentImageIndex, false);

    fullsizeLink.appendChild(document.createTextNode(VIEW_IMAGE));
    var linkPara = document.createElement('p');
    linkPara.appendChild(fullsizeLink);
    dataBlock.appendChild(linkPara);

    /* In Gecko-based browsers, this'll fade the data block in smoothly. */
    dataBlock.style.MozOpacity = 0.2;
    showImageDataFadeTimeout = setTimeout('fadeInImageDataBlock()', 50);

    document.getElementById('main-image-container').appendChild(dataBlock);
}

function fadeInImageDataBlock() {
    clearTimeout(showImageDataFadeTimeout);
    var dataBlock = document.getElementById('imagedatablock');
    /* Don't bring -moz-opacity all the way to 1.0, as it causes flicker in Firefox 1.0 */
    if (dataBlock && getElementStyle(dataBlock.id, '-moz-opacity') < 0.92) {
	dataBlock.style.MozOpacity = parseFloat(getElementStyle(dataBlock.id, '-moz-opacity')) + 0.08;
	showImageDataFadeTimeout = setTimeout('fadeInImageDataBlock()', 50);
    }
}

function removeImageDataBlock() {
    var dataBlock = document.getElementById('imagedatablock');
    if (dataBlock) {
	dataBlock.parentNode.removeChild(dataBlock);
    }
}

/* Subalbums table */

function setupSubAlbums() {
    /* First check if there is a sub-album table */
    if (!document.getElementById('gsSubAlbumMatrix')) {
	return;
    }
    var subs = document.getElementById('gsSubAlbumMatrix').getElementsByTagName('td');
    for (var i = 0; i < subs.length; i++) {
	addEvent(subs[i], 'click', selectSubAlbum, false);
	var hasLink = subs[i].getElementsByTagName('a')[0];
	if (hasLink) {
	    addEvent(subs[i], 'mouseover', highlightSubAlbum, true);
	    addEvent(subs[i], 'mouseout', unHighlightSubAlbum, true);
	}
    }
}

function highlightSubAlbum(e) {
    /* Find the source element through varying levels of browser support */
    var targetElement = window.event ? window.event.srcElement : e ? e.target : null;
    if (!targetElement) {
	return;
    }
    while (targetElement.nodeName.toLowerCase() != 'td' &&
	   targetElement.nodeName.toLowerCase() != 'body') {
	targetElement = targetElement.parentNode;
    }
    if (targetElement.nodeName.toLowerCase() == 'body') {
	return;
    }
    targetElement.className += ' sahover';
}

function unHighlightSubAlbum(e) {
    /* Find the source element through varying levels of browser support */
    var targetElement = window.event ? window.event.srcElement : e ? e.target : null;
    if (!targetElement) {
	return;
    }
    while (targetElement.nodeName.toLowerCase() != 'td' &&
	   targetElement.nodeName.toLowerCase() != 'body') {
	targetElement = targetElement.parentNode;
    }
    if (targetElement.nodeName.toLowerCase() == 'body') {
	return;
    }
    targetElement.className = targetElement.className.replace(/\bsahover\b/, '');
}

function selectSubAlbum(e) {
    /* Find the source element through varying levels of browser support */
    var targetElement = window.event ? window.event.srcElement : e ? e.target : null;
    if (!targetElement) {
	return;
    }
    knackerEvent(e);

    while (targetElement.nodeName.toLowerCase() != 'td' &&
	   targetElement.nodeName.toLowerCase() != 'body') {
	targetElement = targetElement.parentNode;
    }
    if (targetElement.nodeName.toLowerCase() == 'body') {
	return;
    }
    eraseCookie('slideshowOffset');
    var firstlink = targetElement.getElementsByTagName('a')[0];
    if (firstlink) {
	window.location = firstlink.href;
    }
}

/* Photo page functions */

function setupBackToAlbumLink() {
    var pageLinks = document.getElementsByTagName('a');
    for (var i = 0; i < pageLinks.length; i++) {
	if (pageLinks[i].className.match(/\bbacktoalbum\b/)) {
	    addEvent(pageLinks[i], 'click', saveCurrentImageIndex, false);
	}
    }
}

function saveCurrentImageIndex() {
    if (window.location.toString().match(/thumbIndex=([0-9]+)/)) {
	createCookie('slideshowOffset', RegExp.$1);
    } else if (currentImageIndex) {
	createCookie('slideshowOffset', currentImageIndex);
    }
}
