function ImagePreloader(images, callback)
{
   // store the call-back
   this.callback = callback;

   // initialize internal state.
   this.nLoaded = 0;
   this.nProcessed = 0;
   this.aImages = new Array;

   // record the number of images.
   this.nImages = images.length;

   // for each image, call preload()
   for ( var i = 0; i < images.length; i++ )
      this.preload(images[i]);

}
ImagePreloader.prototype.preload = function(image)
{
   // create new Image object and add to array
   var oImage = new Image(352,288);
   this.aImages.push(oImage);

   // set up event handlers for the Image object
   oImage.onload  = ImagePreloader.prototype.onload;
   oImage.onerror = ImagePreloader.prototype.onerror;
   oImage.onabort = ImagePreloader.prototype.onabort;

   // assign pointer back to this.
   oImage.oImagePreloader = this;
   oImage.bLoaded = false;

   // assign the .src property of the Image object
   oImage.src = image;

}
ImagePreloader.prototype.onComplete = function()
{
   this.nProcessed++;
   if ( this.nProcessed == this.nImages )
   {
      this.callback(this.aImages, this.nLoaded);
   }
}
ImagePreloader.prototype.onload = function()
{
   this.bLoaded = true;
   this.oImagePreloader.nLoaded++;
   this.oImagePreloader.onComplete();
}
ImagePreloader.prototype.onerror = function()
{
   this.bError = true;
   this.oImagePreloader.onComplete();
}
ImagePreloader.prototype.onabort = function()
{
   this.bAbort = true;
   this.oImagePreloader.onComplete();
}
// + --------------------------------------------------------------------------------------
// + XHRConnection
// + V1.3
// + Thanh Nguyen, http://www.sutekidane.net
// + 20.10.2005
// + http://creativecommons.org/licenses/by-nc-sa/2.0/fr/deed.fr
// + --------------------------------------------------------------------------------------
function XHRConnection() {

	// + ----------------------------------------------------------------------------------
	var conn = false;
	var debug = false;
	var datas = new String();
	var areaId = new String();
	// Objet XML
	var xmlObj;
	// Type de comportement au chargement du XML
	var xmlLoad;

	// + ----------------------------------------------------------------------------------
	try {
		conn = new XMLHttpRequest();
	}
	catch (error) {
		if (debug) { alert('Erreur lors de la tentative de création de l\'objet \nnew XMLHttpRequest()\n\n' + error); }
		try {
			conn = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch (error) {
			if (debug) { alert('Erreur lors de la tentative de création de l\'objet \nnew ActiveXObject("Microsoft.XMLHTTP")\n\n' + error); }
			try {
				conn = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (error) {
				if (debug) { alert('Erreur lors de la tentative de création de l\'objet \nnew ActiveXObject("Msxml2.XMLHTTP")\n\n' + error); }
				conn = false;
			}
		}
	}

	// + ----------------------------------------------------------------------------------
	// + setDebugOff
	// + Désactive l'affichage des exceptions
	// + ----------------------------------------------------------------------------------
	this.setDebugOff = function() {
		debug = false;
	};

	// + ----------------------------------------------------------------------------------
	// + setDebugOn
	// + Active l'affichage des exceptions
	// + ----------------------------------------------------------------------------------
	this.setDebugOn = function() {
		debug = true;
	};

	// + ----------------------------------------------------------------------------------
	// + resetData
	// + Permet de vider la pile des données
	// + ----------------------------------------------------------------------------------
	this.resetData = function() {
		datas = new String();
		datas = '';
	};

	// + ----------------------------------------------------------------------------------
	// + appendData
	// + Permet d'empiler des données afin de les envoyer
	// + ----------------------------------------------------------------------------------
	this.appendData = function(pfield, pvalue) {
		datas += (datas.length == 0) ? pfield+ "=" + escape(pvalue) : "&" + pfield + "=" + escape(pvalue);
	};

	// + ----------------------------------------------------------------------------------
	// + setRefreshArea
	// + Indique quel elment identifié par id est valoris lorsque l'objet XHR reoit une réponse
	// + ----------------------------------------------------------------------------------
	this.setRefreshArea = function(id) {
		areaId = id;
	};

	// + ----------------------------------------------------------------------------------
	// + createXMLObject
	// + Méthode permettant de créer un objet DOM, retourne la réfrence
	// + Inspiré de: http://www.quirksmode.org/dom/importxml.html
	// + ----------------------------------------------------------------------------------
	this.createXMLObject = function() {
		try {
			 	xmlDoc = document.implementation.createDocument("", "", null);
				xmlLoad = 'onload';
		}
		catch (error) {
			try {
				xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
				xmlLoad = 'onreadystatechange ';
			}
			catch (error) {
				if (debug) { alert('Erreur lors de la tentative de création de l\'objet XML\n\n'); }
				return false;
			}
		}
		return xmlDoc;
	}

	// + ----------------------------------------------------------------------------------
	// + Permet de définir l'objet XML qui doit être valorisé lorsque l'objet XHR reoit une réponse
	// + ----------------------------------------------------------------------------------
	this.setXMLObject = function(obj) {
		if (obj == undefined) {
				if (debug) { alert('Paramètre manquant lors de l\'appel de la méthode setXMLObject'); }
				return false;
		}
		try {
			//xmlObj = this.createXMLObject();
			xmlObj = obj;
		}
		catch (error) {
				if (debug) { alert('Erreur lors de l\'affectation de l\'objet XML dans la méthode setXMLObject'); }
		}
	}

	// + ----------------------------------------------------------------------------------
	// + loadXML
	// + Charge un fichier XML
	// + Entrées
	// + 	xml			String		Le fichier XML à charger
	// + ----------------------------------------------------------------------------------
	this.loadXML = function(xml, callBack) {
		if (!conn) return false;
		// Chargement pour alimenter un objet DOM
		if (xmlObj && xml) {
			if (typeof callBack == "function") {
				if (xmlLoad == 'onload') {
					xmlObj.onload = function() {
						callBack(xmlObj);
					}
				}
				else {
					xmlObj.onreadystatechange = function() {
						if (xmlObj.readyState == 4) callBack(xmlObj)
					}
				}
			}
			xmlObj.load(xml);
			return;
		}
	}

	// + ----------------------------------------------------------------------------------
	// + sendAndLoad
	// + Connexion à la page désirée avec envoie des données, puis mise en attente de la réponse
	// + Entrées
	// + 	Url			String		L'url de la page à laquelle l'objet doit se connecter
	// + 	httpMode		String		La méthode de communication HTTP : GET, HEAD ou POST
	// + 	callBack		Objet		Le nom de la fonction de callback
	// + ----------------------------------------------------------------------------------
	this.sendAndLoad = function(Url, httpMode, callBack) {
		httpMode = httpMode.toUpperCase();
		conn.onreadystatechange = function() {
			if (conn.readyState == 4 && conn.status == 200) {
				// Si une fonction de callBack a été définie
				if (typeof callBack == "function") {
					callBack(conn);
					return;
				}
				// Si une zone destinée à récupérer le résultat a été définie
				else if (areaId.length > 0){
					try {
						document.getElementById(areaId).innerHTML = conn.responseText;
					}
					catch(error) {
						if (debug) { alert('Echec, ' + areaId + ' n\'est pas un objet valide'); }
					}
					return;
				}
			}
		};
		switch(httpMode) {
			case "GET":
				try {
					Url = (datas.length > 0) ? Url + "?" + datas : Url;
					conn.open("GET", Url);
					conn.send(null);
				}
				catch(error) {
					if (debug) { alert('Echec lors de la transaction avec ' + Url + ' via la méthode GET'); }
					return false;
				}
			break;
			case "POST":
				try {
					conn.open("POST", Url);
					conn.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
					conn.send(datas);
				}
				catch(error) {
					if (debug) { alert('Echec lors de la transaction avec ' + Url + ' via la méthode POST'); }
					return false;
				}
			break;
			default :
				return false;
			break;
		}
		return true;
	};
	return this;
}

function addEvent(source, type, callback)
{
    // fonction d'abstraction pour enregistrer un gestionnaire d'evenement
    // comprend le DOM standard, la syntaxe prorietaire MSIE, l'ancien modele HTML
    // source : objet sur lequel ajouter le gestionnaire d'evenement
    // type : type d'evenement
    // callback : fonction qui traitera l'evenement
    if (source.addEventListener) {
        // code standard DOM
        source.addEventListener(type, callback, false);
        return true;
    } else if (source.attachEvent) {
        // code propriétaire MSIE
        var r = source.attachEvent('on'+type, callback);
        return r;
    } else  {
        // code navigateur sans support DOM-event
        eval('source.on' + type + '= callback') ;
    }
}
function getStandardEvent(e)
{
    // abstraction pour recuperer un objet standard pour l'evenement en cours
    // comprend le modele DOM standard et le modele proprietaire de MSIE
    // e : parametre recu lors de l'appel du gestionnaire d'evenement
    // retour : objet d'evenement standard
    if (e == null && window.event)  {
        // cas particulier de MSIE pour recuperer l'evenement en cours
        e = window.event ;
    }
    if (e.target == null && e.srcElement)  {
        // cas particulier de MSIE pour recuperer la balise DOM cible
        e.target = e.srcElement ;
    }
    if (!e.preventDefault) {
        // cas particulier de MSIE pour empecher l'action par defaut du navigateur
        e.preventDefault = function() { this.returnValue = false; };
    }

    return e;
}
// A nice reusable utility function !! (show sample code below...)
// ... push it in your js toolkit
function $() {
	var elements = new Array();
	for (var i = 0; i < arguments.length; i++) {
		var element = arguments[i];
		if (typeof element == 'string')
			element = document.getElementById(element);
		if (arguments.length == 1)
			return element;
		elements.push(element);
	}
	return elements;
}
function initBeachcam()
{
    // Création de l'objet
    var XHR = new XHRConnection();
    //XHR.debug = true;
    XHR.appendData('asynchronous','on');
    XHR.appendData('snapshot',SNAPSHOT_NUM);
    XHR.sendAndLoad('refresh_snapshot.php', 'GET', preloadBeachcam);
}
function preloadBeachcam(obj)
{
    // contenu de la réponse
	if(obj.responseXML == null) {
        initBeachcam();
		return;
	}
    var snapshot = obj.responseXML.getElementsByTagName('snapshot')[0].firstChild;
    if (!snapshot) {
        initBeachcam();
		return;
    } else if (snapshot.textContent) {
        snapshot=snapshot.textContent;
    } else {
        snapshot=snapshot.text;
    }
    var snapshot_preloader = new ImagePreloader(new Array('snapshot'+SNAPSHOT_NUM+'/'+snapshot),refreshBeachcam);
}

function refreshBeachcam(img)
{
    $('beachcam').src = img[0].src;
    // breathe...
    setTimeout('initBeachcam()',1000);
}

// initialisation au chargement de la page
addEvent(window,'load',initBeachcam);

