/*
 * Copyright © 2011 MBA Multimédia (www.mba-multimedia.com)
 */

/* *************************************************************
 * Localisation	
 *************************************************************** */
// Tableau de valeur pour la gestion des calendriers en français
$.tools.dateinput.localize("fr", {
	months: 'janvier,f&eacute;vrier,mars,avril,mai,juin,juillet,ao&ucirc;t,septembre,octobre,novembre,d&eacute;cembre',
	shortMonths: 'jan,f&eacute;v,mar,avr,mai,jun,jul,ao&ucirc;,sep,oct,nov,d&eacute;c',
	days: 'dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi',
	shortDays: 'dim,lun,mar,mer,jeu,ven,sam'
});
// Tableau de valeur pour la gestion des messages d'erreurs en français
$.tools.validator.localize("fr", {
	'*'			: "Merci de corriger cette valeur",
	':email'  	: "Merci d'enter une adresse email valide",
	':number' 	: "Merci d'entrer une valeur numérique",
	':url' 		: "Merci d'entrer une adresse internet valide",
	'[max]'	 	: "Merci d'entrer une valeur inférieure à $1",
	'[min]'		: "Merci d'entrer une valeur supérieure à $1",
	'[required]'	: "Merci de renseigner ce champ"
});

// Tableau de valeur pour la traduction FR/UK des différents champs du formulaire de résa
var localise = [];
localise['fr'] = [];
localise['fr']["re_hotel"] 			= "<p><strong>Veuillez sélectionner l'hôtel de séjour</strong></p>";
localise['fr']["re_date-arrivee"] 	= "<p><strong>Veuillez saisir la date d'arrivée</strong></p>";
localise['fr']["re_date-depart"] 	= "<p><strong>Veuillez saisir une date de départ valide</strong></p>";
localise['uk'] = [];
localise['uk']["re_hotel"] 			= "<p><strong>Please select your hotel</strong></p>";
localise['uk']["re_date-arrivee"] 	= "<p><strong>[en]Veuillez saisir la date d'arrivée</strong></p>";
localise['uk']["re_date-depart"] 	= "<p><strong>[en]Veuillez saisir une date de départ valide</strong></p>";
/* *************************************************************
	
 *************************************************************** */

var api, carrouselTimer, lg, langue;
var carrouselConfig = [];

$(function () {
	// Récupération du paramètre de langue de l'URL
	var params = extractUrlParams();
	lg = (params['lg'] == "" || params['lg'] == null) ? "FR" : params['lg'];
	langue = (lg+"").toLowerCase();
	
	$('body').append('<div id="overlay" class="simple_overlay"><div class="content"></div><a href="#" class="close" title="Fermer"></a></div>');
	
	// Impossible d'utiliser <!--[if lte IE 7]> ... à cause du XSL. Obligé d'utiliser un JS
	var ie = $.browser.msie;
	var ie7 = ie && parseInt($.browser.version.slice(0, 1)) <= 7;
	var ie8 = ie && parseInt($.browser.version.slice(0, 1)) <= 8;
	var ff = $.browser.mozilla;
	var ff3 = ff && parseInt($.browser.version.slice(0, 1)) <= 3;
	if (ie) {
		$('head').append('<link href="/css/mba/ie.css" type="text/css" rel="stylesheet">');
		ph();
	}
	if (ie8) {
		
	}
	if (ie7) {
		$('head').append('<link href="/css/mba/ie7.css" type="text/css" rel="stylesheet">');
	}
	if (ie7 || ff3) {
		obsolete(langue);
	}

	//$("#volets").hide();
	//$("#btnVolets").hide();
	//$("#carrousel-haut .carrousel").hide();
	$("#featureCarousel").hide();
	
	// Appel de la fonction de chargement du contenu du slider
	loadSlider();
	// Appel de la fonction de chargement du contenu du carousel
	loadCarousels();
	// Appel de la fonction de chargement du contenu de la liste des hotels
	loadHotels();
	//initValidator (); // >> ne pas initialiser avant la fin du chargement Ajax des hôtels
	
	$("#overlay").overlay({
		top:50,
		mask: {
			color: '#321C01',
			loadSpeed: 200,
			opacity: 0.5
		},
		closeOnClick:true//,
		//load: true
	});
	
	// Ouverture/fermeture "réservation express"
	var re_o = $("#reservation-express .ouvert");
	var re_f = $("#reservation-express .ferme");
	
	// Masquer 
	re_o.css({ display: "block", opacity: 0, bottom: -408 });
	re_f.css({ display: "block", opacity: 0 }).animate({ opacity: 1 }, 400);

	re_f.find("h2").click(function () {
		re_o.css({"z-index":2, bottom:-10}).animate({ bottom: 0, opacity: 1 }, 400);
		re_f.css({"z-index":1}).animate({ opacity: 0 }, 400, function(){ re_f.css({ bottom: -80 }); });
	});
	re_o.find("h2").click(function () {
		re_o.css({"z-index":1}).animate({ opacity: 0 }, 400, function(){ re_o.css({ bottom: -408 }); });
		re_f.css({"z-index":2, bottom:-10}).animate({ opacity:1, bottom:0 }, 400);
	});
	
	// INPUT DATE
	var d = new Date();
	switch (langue) {
		case "fr" : // On charge le calendrier français
			$(":date").dateinput({
				// DOC sur http://flowplayer.org/tools/dateinput/
				lang: 'fr',
				format: 'dd/mm/yyyy',
				firstDay: 1, // lundi
				min: -1, // aujourd'hui
				max: 365, // dans 1 an
				offset: [3, -120]
			});
			break;
		case "uk" :
		default : // On charge le calendrier anglais
			// Défaut => en anglais
			$(":date").dateinput({
				// DOC sur http://flowplayer.org/tools/dateinput/
				format: 'mm/dd/yyyy',
				min: -1, // aujourd'hui
				max: 365, // dans 1 an
				offset: [3, -120]
			});
			break;
	}
	var daApi = $("#re_date-arrivee").data("dateinput");
	var ddApi = $("#re_date-depart").data("dateinput")
	daApi.setValue(d);
	ddApi.setValue(new Date(d.setDate(d.getDate()+1)));
	daApi.change(function () {
		var da = new Date(daApi.getValue());
		var dmin = new Date (da.setDate(da.getDate()+1));
		$("#re_date-depart").data("dateinput").setMin(dmin, true);
	});

});

// Fonction qui initialise le JavaScript du carousel
function launchCarousel(){
	// Carrousel "bas"
	$("#featureCarousel").featureCarousel({
		largeFeatureWidth: 348,
		largeFeatureHeight: 164,

		smallFeatureWidth: 348, //278,
		smallFeatureHeight: 146,
		
		smallImageWidth: 156,
		largeImageWidth: 156,

		autoPlay:3500, // Temps en milliseconde entre chaque élément du carousel
		animationEasing: 'swing',
		
		stopOnHover:true
	}).fadeIn("slow");
}

/* *************************************************************
 * Validation du formulaire	
 *************************************************************** */
function initValidator (){
	//console.log("initValidator()");
	
	$("#reservation-express .ouvert form").attr('novalidate', 'novalidate').validator({
		effect: 'wall', 
		container: '#overlay',
		lang:langue,
		errorInputEvent: 'keyup change'
	}).submit(function(e)  { 
		if (e.isDefaultPrevented()) {
			//console.log("erreur");
			return false;
		} else {
			//console.log("ok");
			e.preventDefault();
			return verif_form($("#re_form"));
		}
	});
}

// Fonction qui vérifie la validité des champs du formulaire de résa
function verif_form(f) {
	// Récupération du paramètre de langue de l'URL
	var params = extractUrlParams();
	if (params["lg"] == null) {
		var lg = "FR";
	} else {
		var lg = params["lg"];
	}
	var elm = document.getElementById(f.attr("id"));
	
	var url = ''; // On construit l'url vers le site de réservation

	if (elm.elements["property"].value != "") {
		url += elm.elements["property"].value; // Ce champ contient l'url de base présent dans le fichier XML lié à l'hotel sélectionné

		if (elm.elements["arrival"].value != "") {
			var arrival = "" + elm.elements["arrival"].value + "";
			var arrivalTab = arrival.split("/");
			if(lg == "FR"){
				arrival = arrivalTab[2] + "-" + arrivalTab[1] + "-" + arrivalTab[0];
			} else {
				arrival = arrivalTab[2] + "-" + arrivalTab[0] + "-" + arrivalTab[1];
			}
			url += '&arrival=' + arrival; // On ajoute le parametre "arrival" qui est la date d'arrivée souhaitée
		}
		if (elm.elements["departure"].value != "") {
			var departure = "" + elm.elements["departure"].value + "";
			var departureTab = departure.split("/");
			if(lg == "FR"){
				departure = departureTab[2] + "-" + departureTab[1] + "-" + departureTab[0];
			} else {
				departure = departureTab[2] + "-" + departureTab[0] + "-" + departureTab[1];
			}
			url += '&departure=' + departure; // On ajoute le parametre "departure" qui est la date de départ souhaitée
		}
		if (elm.elements["rooms"].value != "") {
			url += '&rooms=' + elm.elements["rooms"].value; // On ajoute le parametre "rooms" qui est le nombre de chambre souhaité
		}
		if (elm.elements["adults"].value != "") {
			url += '&adults=' + elm.elements["adults"].value; // On ajoute le parametre "adults" qui est le nombre d'adulte souhaité
		}
		if (elm.elements["children"].value != "") {
			url += '&children=' + elm.elements["children"].value; // On ajoute le parametre "children" qui est le nombre d'enfant souhaité
		}
		if (elm.elements["promotioncode"].value != "") {
			url += '&promotioncode=' + elm.elements["promotioncode"].value; // On ajoute le parametre "promotioncode" qui est le code promotion entré
		}
		if (elm.elements["companycode"].value != "") {
			url += '&companycode=' + elm.elements["companycode"].value; // On ajoute le parametre "companycode" qui est le code entreprise entré
		}

		url += '&autosubmit=1'; // On ajoute le parametre "autosubmit" afin que le formulaire se valide automatiquement avec les infos renseignées lors de l'arrivée sur le site de réservation

		//window.open(url); // On ouvre une nouvelle fenêtre vers le lien construit
		callXiti(url,'Quick');
   
		/**********************************************************************
		* Pour la gestion de l'hotel spécifique que vous nous avez mentionné, *
		* il est assez complexe de prévoir le fonctionnement d'un cas bien    *
		* particulier. En effet, il faudrait pouvoir repérer dans la fonction *
		* que l'hotel en question est celui sélectionné. L'utilisation d'un   *
		* nouveau champ dans le fichier XML pourrait permettre cela. Une fois *
		* que l'on a détecté cet hotel, on peut alors faire une construction  * 
		* différente de l'url pour lui spécifier des champs différents.       *
		* La récupération des champs du formulaire sera la même, il faudra    *
		* alors modifier le nom du paramètre que l'on ajoute dans l'url       *
		* afin qu'il corresponde au nom attendu par le site de réservation    *
		* ciblé.                                                              *
		**********************************************************************/
	}

	return false;
}
$.tools.validator.fn("select", "Select a value", function(input, value) { 
	return (value == '') ? false : true;
}); 
$.tools.validator.addEffect("wall", function(errors, event) {
	var wall = $(this.getConf().container);
	wall.find(".content").html('');
	if (errors.length>0){
		$.each(errors, function(index, error) {
			var msg ="";
			var id = error.input.attr("id");
			// Messages personnalisés
			switch (id){
				case "re_hotel" :
				case "re_date-arrivee" :
				case "re_date-depart" :
					msg = localise[langue][id];
					break;
				default :
					msg = "<p><strong>" +error.input.attr("title")+ "</strong> " +error.messages[0]+ "</p>";
					break;
			}
			// Afficher le message d'erreur
			wall.find(".content").append(msg);
		});
		wall.data("overlay").load();
	}
}, function(inputs)  {
	
});

/* *************************************************************
 * Navigateur obsolète	
 *************************************************************** */
function obsolete (langue){
	var msg = "";
	switch (langue){
		case "fr" :
			msg = "Vous utilisez un navigateur Internet obsolète. Pour garantir un bon affichage du site, veuillez mettre à jour votre navigateur.";
			break;
		case "uk" :
		default:
			msg = "The browser you are using is too old. To make sure this web site displays properly, please upgrade to the latest version of your browser.";
			break;
	}
	$('body').prepend('<div class="obsolete">'+msg+'</div>');
}

/* *************************************************************
 * Carrousel	
 *************************************************************** */
function carrouselNext(){
	//alert('next');
	api.next(500);
}

/* *************************************************************
 * Slider	
 *************************************************************** */


function ph() {
	$('[placeholder]').each(function () {
		var ph = $(this).attr("placeholder");
		if (ph != "") {
			$(this).focus(function () {
				if ($(this).val() == ph) {
					$(this).val('');
				}
			}).blur(function () {
				if ($(this).val() == '') {
					$(this).val(ph);
				}
			}).blur();
		}
	});

	// Validation du formulaire : vider les champs dont le contenu vaut la valeur du placeholder
	$('[placeholder]').parents('form').submit(function () {
		$(this).find('[placeholder]').each(function () {
			if ($(this).val() == $(this).attr('placeholder')) {
				$(this).val('');
			}
		})
	});
}

// Fonction qui récupère le paramètre de langue dans l'URL
function extractUrlParams() {
	var t = location.search.substring(1).split('&');
	var f = [];
	for (var i = 0; i < t.length; i++) {
		var x = t[i].split('=');
		f[x[0]] = x[1];
	}
	return f;
}

// Fonction qui charge la liste des hotels
function loadHotels() {
	var xhr = getXMLHttpRequest();
	if (xhr && xhr.readyState != 0) {
		xhr.abort();
	}

	xhr.onreadystatechange = function () {
		if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) {
			var xmlResult = xhr.responseXML;

			var rows = xmlResult.getElementsByTagName("row");

			var html = '';
			if(lg == "FR"){
				html += '<option value="">Sélectionnez votre hôtel</option>';
			} else if(lg == "UK"){
				html += '<option value="">Select your hotel</option>';
			}

			// On construit la liste avec les informations récupérées du fichier XML
			for (var i = 0; i < rows.length; i++) {
				var lien = rows[i].getElementsByTagName("lien")[0].childNodes[0].nodeValue;
				var hotel = rows[i].getElementsByTagName("hotel")[0];
				var nomHotel = hotel.childNodes[0];

				html += '<option value="' + lien + '">' + nomHotel.nodeValue + '</option>';
			}

			//html += '</select>';

			$("#re_hotel").html(html);
			
			initValidator();
			
		} else if (xhr.readyState == 2 || xhr.readyState == 3) {

		}
	}

	xhr.open("GET", "/getinfo.php?type=hotel&lg=" + lg, true); // Appel du script pour récupérer le contenu au format XML
	xhr.send(null);
}

// Fonction qui charge le contenu du slider
function loadSlider() {
	// Récupération du paramètre de langue de l'URL
	var params = extractUrlParams();
	if (params["lg"] == null) {
		var lg = "FR";
	} else {
		var lg = params["lg"];
	}
	
	var xhrS = getXMLHttpRequest();

	if (xhrS && xhrS.readyState != 0) {
		xhrS.abort();
	}

	xhrS.onreadystatechange = function () {
		if (xhrS.readyState == 4 && (xhrS.status == 200 || xhrS.status == 0)) {
			var xmlResult = xhrS.responseXML;
			var rows = xmlResult.getElementsByTagName("row");
			var html = '';
			var html2 = '';

			for (var i = 0; i < rows.length; i++) {
					var value = rows[i].getAttribute("id");
					var titre = rows[i].getElementsByTagName("titre")[0].childNodes[0].nodeValue;
					var ordre = rows[i].getElementsByTagName("ordre")[0].childNodes[0].nodeValue;
					var lien = rows[i].getElementsByTagName("lien")[0].childNodes[0].nodeValue;
					var animation = rows[i].getElementsByTagName("animation")[0].childNodes[0].nodeValue;
					var temps = rows[i].getElementsByTagName("temps")[0].childNodes[0].nodeValue;
					temps = (temps*1000);
					
					// On récupère l'extension du média à afficher
					var exts = animation.split(".");
					var ext = exts[exts.length-1];
	
					html += '<li><div class="none">'+ titre +'</div>';
					// Si le média est un flash, la construction diffère
					if(ext == 'swf'){
						html += '<div class="swf"></div><a href="/upload/' + animation + '" title="' + titre + '"></a>';
						carrouselConfig[i] = {type:"swf"};
					} else {
						html += '<a href="' + lien + '" title="' + titre + '"><img src="/upload/' + animation + '" width="777" height="360" title="' + titre + '" alt="' + titre + '" /></a>';
						carrouselConfig[i] = {type:"img",delai:temps};
					}
					html += '</li>';
					
					html2 += '<li>';
					html2 += '<a href="#" title="' + titre + '"';
					if(i == 0){
						html2 += ' class="active"';
					}
					html2 += '>' + titre + '</a>';
					html2 += '</li>';
			}
			
			// Décaler volet à la création à cause du paramètre circular 
			$("#volets").html(html);
			$("#btnVolets").html(html2);
			
			// Appel de la fonction d'initialisation du slider
			launchSlider();

		} else if (xhrS.readyState == 2 || xhrS.readyState == 3) {

		}
	}

	xhrS.open("GET", "/getinfo.php?type=slider&lg=" + lg, true); // Appel du script pour récupérer le contenu au format XML
	xhrS.send(null);
}

// Fonction qui initialise le JavaScript du slider
function launchSlider(){
	// Carrousel "haut"
	api = $("#carrousel-haut .carrousel").scrollable({ circular:true, initialIndex:0, items: '#volets' }).navigator({ navi: "#boutons", naviItem: 'a' }).data("scrollable");
	api.onBeforeSeek = function() {
		
		var n=api.getIndex();
		
		// à cause du paramètre "circular", n peut être négatif au lieu de prendre la valeur du dernier élément
		if(n<0) {
			n=api.getSize()-1;
		}
		
		switch (carrouselConfig[n].type) {
			case "img":
				break;
			case "swf":
				var items = api.getItems();
				$(items[api.getIndex()]).find('.swf').html('');
				break;
		}
	}
	
	api.onSeek = function() {
		clearTimeout(carrouselTimer);
		
		var n=api.getIndex();
		switch (carrouselConfig[n].type) {
			case "img":
				carrouselTimer = setTimeout(carrouselNext, carrouselConfig[n].delai);
				break;
			case "swf":
				var items = api.getItems();
				var currentItem = $(items[api.getIndex()]);
				var swf = currentItem.find('a').attr('href');
				currentItem.find('a').hide();
				
				//console.log (swf);
				// Charger le flash et attendre qu'il donne l'odre de passer à la suite
				var flashvars = { };
				var params = { src:swf, wmode:"transparent", width:777, height:360 };
				currentItem.find('.swf').flashembed(params, flashvars);
				break;
		}
	};
	
	// Mise en route du carrousel "haut"
	// Commencer à la fin et passer au suivant pour éviter un bug décalage entre bouton sélectionné et volet affiché. Problème lié au paramètre "circular" ?
	//api.end(0).next(0);
	$("#volets").css({left:-777});
	$("#carrousel-haut .carrousel").fadeIn(400, function(){ api.begin(0); });
}

// Fonction qui charge le contenu du carousel
function loadCarousels() {
	// Récupération du paramètre de langue de l'URL
	var params = extractUrlParams();
	if (params["lg"] == null) {
		var lg = "FR";
	} else {
		var lg = params["lg"];
	}
	
	var xhrC = getXMLHttpRequest();

	if (xhrC && xhrC.readyState != 0) {
		xhrC.abort();
	}

	xhrC.onreadystatechange = function () {
		if (xhrC.readyState == 4 && (xhrC.status == 200 || xhrC.status == 0)) {
			var xmlResult = xhrC.responseXML;
			var rows = xmlResult.getElementsByTagName("row");
			var html = '';

			for (var i = 0; i < rows.length; i++) {
				var value = rows[i].getAttribute("id");
				var hotel = rows[i].getElementsByTagName("hotel")[0].childNodes[0].nodeValue;
				var id = rows[i].getElementsByTagName("identifiant")[0].childNodes[0].nodeValue;
				var titre = rows[i].getElementsByTagName("titre")[0].childNodes[0].nodeValue;
				var debut = "" + rows[i].getElementsByTagName("debut")[0].childNodes[0].nodeValue + "";
				var debutTab = debut.split("-");
				debut = debutTab[2] + "/" + debutTab[1] + "/" + debutTab[0];
				var fin = "" + rows[i].getElementsByTagName("fin")[0].childNodes[0].nodeValue + "";
				var finTab = fin.split("-");
				fin = finTab[2] + "/" + finTab[1] + "/" + finTab[0];
				var tarif_t = rows[i].getElementsByTagName("tarif_t")[0].childNodes[0].nodeValue;
				var tarif = rows[i].getElementsByTagName("tarif")[0].childNodes[0].nodeValue;
				var tarif_pdj = rows[i].getElementsByTagName("tarif_pdj")[0].childNodes[0].nodeValue;
				var image = rows[i].getElementsByTagName("image")[0].childNodes[0].nodeValue;

				html += '<div class="feature">';
				html += '<div class="ctn">';
				html += '<div class="left"><img src="/upload/' + image + '" alt="' + hotel + '" /></div>';
				html += '<div class="right">';
				html += '<p><strong>' + hotel + '</strong></p>';
				html += '<h3><a href="/hotel-offre-detail.php?offre=' + id + '&amp;lg='+lg+'" title="En savoir plus">' + titre + '</a></h3>';
				
				if (lg == 'FR') {
					html += '<p>' + tarif_t + ' <span class="prix">' + tarif + '€</span> ' + tarif_pdj + '</p>';
				} else if (lg == 'UK') {
				html += '<p>' + tarif_t + ' <span class="prix">€' + tarif + '</span> ' + tarif_pdj + '</p>';
				}
		
				html += '</div>';
				html += '</div>';
				html += '<div class="btm">';
				html += '<div class="left"><p>Promotion</p></div>';
				if (lg == 'FR') {
					html += '<div class="right"><p>Du ' + debut + ' au ' + fin + '</p></div>';
				} else if (lg == 'UK') {
					html += '<div class="right"><p>From ' + debut + ' to ' + fin + '</p></div>';
				}
				html += '</div>';
				html += '</div>';
			}

			$("#featureCarousel").html(html);
			// Appel de la fonction d'initialisation du JavaScript du carousel
			launchCarousel();
			
		} else if (xhrC.readyState == 2 || xhrC.readyState == 3) {

		}
	}

	xhrC.open("GET", "/getinfo.php?type=carrousel&lg=" + lg, true);
	xhrC.send(null);
}

/*!
 * Feature Carousel, Version 1.0
 * http://www.bkosolutions.com
 *
 * Copyright 2010 Brian Osborne
 * Licensed under GPL version 3
 *
 * http://www.gnu.org/licenses/gpl.txt
 */
(function ($) {

	$.fn.featureCarousel = function (options) {

		// override the default options with user defined options
		options = $.extend({}, $.fn.featureCarousel.defaults, options || {});

		return $(this).each(function () {

			/* These are univeral values that are used throughout the plugin. Do not modify them
			 * unless you know what you're doing. Most of them feed off the options
			 * so most customization can be achieved by modifying the options values */
			var pluginData = {
				currentCenterNum: options.startingFeature,
				containerWidth: 0,
				containerHeight: 0,
				largeFeatureWidth: 0,
				largeFeatureHeight: 0,
				smallFeatureWidth: 0,
				smallFeatureHeight: 0,
				smallImageWidth: 0,
				largeImageWidth: 0,
				totalFeatureCount: $(this).children("div").length,
				currentlyMoving: false,
				featuresContainer: $(this),
				featuresArray: [],
				containerIDTag: "#" + $(this).attr("id"),
				timeoutVar: null,
				rotationsRemaining: 0,
				itemsToAnimate: 0,
				borderWidth: 0
			};

			preload(function () {
				setupFeatureDimensions();
				setupCarousel();
				setupFeaturePositions();
				setupBlips();
				initiateMove(true, 1);
			});

			/**
			 * Function to preload the images in the carousel if desired.
			 * This is not recommended if there are a lot of images in the carousel because
			 * it may take a while. Functionality does not depend on preloading the images
			 */

			function preload(callback) {
				// user may not want to preload images
				if (options.preload == true) {
					var $imageElements = pluginData.featuresContainer.find("img");
					var loadedImages = 0;
					var totalImages = $imageElements.length;

					$imageElements.each(function () {
						// Attempt to load the images
						$(this).load(function () {
							// Add to number of images loaded and see if they are all done yet
							loadedImages++;
							if (loadedImages == totalImages) {
								// All done, perform callback
								callback();
							}
						});
						// The images may already be cached in the browser, in which case they
						// would have a 'true' complete value and the load callback would never be
						// fired. This will fire it manually.
						if (this.complete) {
							$(this).trigger('load');
						}
					});
				} else {
					// if user doesn't want preloader, then just go right to callback
					callback();
				}
			}

			// Gets the feature container based on the number

			function getContainer(featureNum) {
				return pluginData.featuresArray[featureNum - 1];
			}

			// get a feature given it's set position (the position that doesn't change)

			function getBySetPos(position) {
				$.each(pluginData.featuresArray, function () {
					if ($(this).data().setPosition == position) return $(this);
				});
			}

			// get previous feature number

			function getPreviousNum(num) {
				if ((num - 1) == 0) {
					return pluginData.totalFeatureCount;
				} else {
					return num - 1;
				}
			}

			// get next feature number

			function getNextNum(num) {
				if ((num + 1) > pluginData.totalFeatureCount) {
					return 1;
				} else {
					return num + 1;
				}
			}

			/**
			 * Because there are several options the user can set for the width and height
			 * of the feature images, this function is used to determine which options were set
			 * and to set the appropriate dimensions used for a small and large feature
			 */

			function setupFeatureDimensions() {
				// Set the height and width of the entire carousel container
				pluginData.containerWidth = pluginData.featuresContainer.width();
				pluginData.containerHeight = pluginData.featuresContainer.height();
				pluginData.largeImageWidth = options.largeImageWidth;
				pluginData.smallImageWidth = options.smallImageWidth;
				pluginData.largeFeatureWidth = options.largeFeatureWidth;
				pluginData.largeFeatureHeight = options.largeFeatureHeight;
				pluginData.smallFeatureWidth = options.smallFeatureWidth;
				pluginData.smallFeatureHeight = options.smallFeatureHeight;
			}

			/**
			 * Function to take care of setting up various aspects of the carousel,
			 * most importantly the default positions for the features
			 */

			function setupCarousel() {
				// Set the total feature count to the amount the user wanted to cutoff
				if (options.displayCutoff > 0 && options.displayCutoff < pluginData.totalFeatureCount) {
					pluginData.totalFeatureCount = options.displayCutoff;
				}

				// fill in the features array
				pluginData.featuresContainer.children("div").each(function (index) {
					if (index < pluginData.totalFeatureCount) {
						pluginData.featuresArray[index] = $(this);
					}
				});

				// Determine the total border width around the feature if there is one
				if (pluginData.featuresContainer.children("div").first().css("borderLeftWidth") != "medium") {
					pluginData.borderWidth = parseInt(pluginData.featuresContainer.children("div").first().css("borderLeftWidth")) * 2;
				}

				// Place all the features in a center hidden position to start off
				pluginData.featuresContainer
				// Have to make the container relative positioning
				.children("div").each(function () {
					// Center all the features in the middle and hide them
					$(this).css({
						'left': (pluginData.containerWidth / 2) - (pluginData.smallFeatureWidth / 2) - (pluginData.borderWidth / 2),
						'width': pluginData.smallFeatureWidth,
						'height': pluginData.smallFeatureHeight,
						'top': options.smallFeatureOffset + options.topPadding,
						'opacity': 0
					});
				})
				// Set all the images to small feature size
				.find("img:first").css({
					'width': pluginData.smallImageWidth
				});

				// figure out number of items that will rotate each time
				if (pluginData.totalFeatureCount < 4) {
					pluginData.itemsToAnimate = pluginData.totalFeatureCount;
				} else {
					pluginData.itemsToAnimate = 4;
				}

				// Hide story info and set the proper positioning
				//pluginData.featuresContainer.find("div > div")
				//  .hide();
			}

			/**
			 * Here all the position data is set for the features.
			 * This is an important part of the carousel to keep track of where
			 * each feature within the carousel is
			 */

			function setupFeaturePositions() {
				// give all features a set number that won't change so they remember their
				// original order
				$.each(pluginData.featuresArray, function (i) {
					$(this).data('setPosition', i + 1);
				});

				// Go back one - This is done because we call the move function right away, which
				// shifts everything to the right. So we set the current center back one, so that
				// it displays in the center when that happens
				var oneBeforeStarting = getPreviousNum(options.startingFeature);
				pluginData.currentCenterNum = oneBeforeStarting;

				// Center feature will be position 1
				var $centerFeature = getContainer(oneBeforeStarting);
				$centerFeature.data('position', 1);

				// Everything before that center feature...
				var $prevFeatures = $centerFeature.prevAll();
				$prevFeatures.each(function (i) {
					$(this).data('position', (pluginData.totalFeatureCount - i));
				});

				// And everything after that center feature...
				var $nextFeatures = $centerFeature.nextAll();
				$nextFeatures.each(function (i) {
					if ($(this).data('setPosition') != undefined) {
						$(this).data('position', (i + 2));
					}
				});

				// if the counter style is for including number tags in description...
				if (options.counterStyle == 3) {
					$.each(pluginData.featuresArray, function () {
						var pos = getPreviousNum($(this).data('position'));
						var $numberTag = $("<span></span>");
						$numberTag.addClass("numberTag");
						$numberTag.html("(" + pos + " of " + pluginData.totalFeatureCount + ") ");
						$(this).find('div p').prepend($numberTag);
					});
				}
			}

			/**
			 * The blips are built using this function. The position and look
			 * of the blips are completely determined by the CSS file
			 */

			function setupBlips() {
				// Only setup the blips if the counter style is 1 or 2
				if (options.counterStyle == 1 || options.counterStyle == 2) {
					// construct the blip list
					var $list = $("<ul></ul>");
					$list.addClass("blipsContainer");
					for (var i = 0; i < pluginData.totalFeatureCount; i++) {
						// Counter style 1 has no numbers, while 2 does
						var counter;
						if (options.counterStyle == 2) counter = "";
						else counter = i + 1;

						// Build the DOM for the blip list
						var $blip = $("<div>"+(i+1)+"</div>");
						$blip.addClass("blip");
						$blip.css("cursor", "pointer");
						$blip.attr("id", "blip_" + (i + 1));
						var $listEntry = $("<li></li>");
						$listEntry.append($blip);
						$listEntry.css("float", "left");
						$listEntry.css("list-style-type", "none");
						$list.append($listEntry);
					}
					// add the blip list and then make sure it's visible
					$(pluginData.containerIDTag).append($list);
					$list.hide().show();
				}
			}

			// Move the highlighted blip to the currently centered feature

			function changeBlip(oldCenter, newCenter) {
				// get selectors for the two blips
				var $blipsContainer = pluginData.featuresContainer.find(".blipsContainer");
				var $oldCenter = $blipsContainer.find("#blip_" + oldCenter);
				var $newCenter = $blipsContainer.find("#blip_" + newCenter);

				// change classes
				$oldCenter.removeClass("blipSelected");
				$newCenter.addClass("blipSelected");
			}

			/**
			 * This function will set the autoplay for the carousel to
			 * automatically rotate it given the time in the options
			 */

			function autoPlay() {
				// clear the timeout var if it exists
				if (pluginData.timeoutVar != null) {
					pluginData.timeoutVar = clearTimeout(pluginData.timeoutVar);
				}

				// set interval for moving if autoplay is set
				if (options.autoPlay != 0) {
					var autoTime = (Math.abs(options.autoPlay) < options.carouselSpeed) ? options.carouselSpeed : Math.abs(options.autoPlay);
					pluginData.timeoutVar = setTimeout(function () {
						if (options.autoPlay > 0) initiateMove(true, 1);
						else if (options.autoPlay < 0) initiateMove(false, 1);
					}, autoTime);
				}
			}

			// This is a helper function for the animateFeature function that
			// will update the positions of all the features based on the direction

			function rotatePositions(direction) {
				$.each(pluginData.featuresArray, function () {
					var newPos;
					if (direction == false) {
						newPos = getNextNum($(this).data().position);
					} else {
						newPos = getPreviousNum($(this).data().position);
					}
					$(this).data('position', newPos);
				});
			}

			/**
			 * This function is used to animate the given feature to the given
			 * location. Valid locations are "left", "right", "center", "hidden"
			 */

			function animateFeature($feature, direction) {
				var new_img_width, new_width, new_height, new_top, new_left, new_zindex, new_padding, new_fade;

				// Determine the old and new positions of the feature
				var oldPosition = $feature.data('position');
				var newPosition;
				if (direction == true) newPosition = getPreviousNum(oldPosition);
				else newPosition = getNextNum(oldPosition);

				// Caculate new new css values depending on where the feature will be located
				if (newPosition == 1) {
					new_img_width = pluginData.largeImageWidth;
					new_width = pluginData.largeFeatureWidth;
					new_height = pluginData.largeFeatureHeight;
					new_top = options.topPadding;
					new_zindex = $feature.css("z-index");
					new_left = (pluginData.containerWidth / 2) - (pluginData.largeFeatureWidth / 2) - (pluginData.borderWidth / 2);
					new_fade = 1;
				} else {
					new_img_width = pluginData.smallImageWidth;
					new_width = pluginData.smallFeatureWidth;
					new_height = pluginData.smallFeatureHeight;
					new_top = options.smallFeatureOffset + options.topPadding;
					new_zindex = 1;
					new_fade = 0.5;
					// some info is different for the left, right, and hidden positions
					// left
					if (newPosition == pluginData.totalFeatureCount) {
						new_left = options.sidePadding;
						// right
					} else if (newPosition == 2) {
						new_left = pluginData.containerWidth - pluginData.smallFeatureWidth - options.sidePadding - pluginData.borderWidth;
						// hidden
					} else {
						new_left = (pluginData.containerWidth / 2) - (pluginData.smallFeatureWidth / 2) - (pluginData.borderWidth / 2);
						new_fade = 0;
					}
				}
				// This code block takes care of hiding the feature information if the feature is
				// NO LONGER going to be in the center
				if (newPosition != 1) {
					// Slide up the story information
					//$feature.find("div")
					//  .hide();
				}

				// Animate the feature div to its new location
				$feature.animate({
					width: new_width,
					height: new_height,
					top: new_top,
					left: new_left,
					opacity: new_fade
				}, options.carouselSpeed, options.animationEasing, function () {
					// Take feature info out of hiding if new position is center
					if (newPosition == 1) {
						// fade in the feature information
						$feature.find("div").fadeTo("fast", 1);
					}
					// decrement the animation queue
					pluginData.rotationsRemaining = pluginData.rotationsRemaining - 1;
					// have to change the z-index after the animation is done
					$feature.css("z-index", new_zindex);
					// change blips if using them
					if (options.counterStyle == 1 || options.counterStyle == 2) {
						if (newPosition == 1) {
							// figure out what item was just in the center, and what item is now in the center
							var newCenterItemNum = pluginData.featuresContainer.children("div").index($feature) + 1;
							var oldCenterItemNum;
							if (direction == false) oldCenterItemNum = getNextNum(newCenterItemNum);
							else oldCenterItemNum = getPreviousNum(newCenterItemNum);
							// now change the active blip
							changeBlip(oldCenterItemNum, newCenterItemNum);
						}
					}

					// did all the the animations finish yet?
					var divide = pluginData.rotationsRemaining / pluginData.itemsToAnimate;
					if (divide % 1 == 0) {
						// if so, set moving to false...
						pluginData.currentlyMoving = false;
						// change positions for all items...
						rotatePositions(direction);

						// and move carousel again if queue is not empty
						if (pluginData.rotationsRemaining > 0) move(direction);
					}

					// call autoplay again
					autoPlay();
				})
				// select the image within the feature
				.find("img:first")
				// animate its size down
				.animate({
					width: new_img_width
					//height: new_height
				}, options.carouselSpeed, options.animationEasing).end();
			}

			/**
			 * move the carousel to the left or to the right. The features that
			 * will move into the four positions are calculated and then animated
			 * rotate to the RIGHT when direction is TRUE and
			 * rotate to the LEFT when direction is FALSE
			 */

			function move(direction) {
				// Set the carousel to currently moving
				pluginData.currentlyMoving = true;

				// Obtain the new feature positions based on the direction that the carousel is moving
				var $newCenter, $newLeft, $newRight, $newHidden;
				if (direction == true) {
					// Shift features to the left
					$newCenter = getContainer(getNextNum(pluginData.currentCenterNum));
					$newLeft = getContainer(pluginData.currentCenterNum);
					$newRight = getContainer(getNextNum(getNextNum(pluginData.currentCenterNum)));
					$newHidden = getContainer(getPreviousNum(pluginData.currentCenterNum));
					pluginData.currentCenterNum = getNextNum(pluginData.currentCenterNum);
				} else {
					$newCenter = getContainer(getPreviousNum(pluginData.currentCenterNum));
					$newLeft = getContainer(getPreviousNum(getPreviousNum(pluginData.currentCenterNum)));
					$newRight = getContainer(pluginData.currentCenterNum);
					$newHidden = getContainer(getNextNum(pluginData.currentCenterNum));
					pluginData.currentCenterNum = getPreviousNum(pluginData.currentCenterNum);
				}

				// The z-index must be set before animations take place for certain movements
				// this makes the animations look nicer
				if (direction) {
					$newLeft.css("z-index", 3);
				} else {
					$newRight.css("z-index", 3);
				}
				$newCenter.css("z-index", 4);

				// Animate the features into their new positions
				animateFeature($newLeft, direction);
				animateFeature($newCenter, direction);
				animateFeature($newRight, direction);
				// Only want to animate the "hidden" feature if there are more than three
				if (pluginData.totalFeatureCount > 3) {
					animateFeature($newHidden, direction);
				}
			}

			// This is used to relegate carousel movement throughout the plugin
			// It will only initiate a move if the carousel isn't currently moving
			// It will set the animation queue to the number of rotations given

			function initiateMove(direction, rotations) {
				if (pluginData.currentlyMoving == false) {
					var queue = rotations * pluginData.itemsToAnimate;
					pluginData.rotationsRemaining = queue;
					move(direction);
				}
			}

			/**
			 * This will find the shortest distance to travel the carousel from
			 * one position to another position. It will return the shortest distance
			 * in number form, and will be positive to go to the right and negative for left
			 */

			function findShortestDistance(from, to) {
				var goingToLeft = 1,
					goingToRight = 1,
					tracker;
				tracker = from;
				// see how long it takes to go to the left
				while ((tracker = getPreviousNum(tracker)) != to) {
					goingToLeft++;
				}

				tracker = from;
				// see how long it takes to to to the right
				while ((tracker = getNextNum(tracker)) != to) {
					goingToRight++;
				}

				// whichever is shorter
				return (goingToLeft < goingToRight) ? goingToLeft * -1 : goingToRight;
			}

			// Move to the left if left button clicked
			$(".leftButton").click(function () {
				initiateMove(false, 1);
			});

			// Move to right if right button clicked
			$(".rightButton").click(function () {
				initiateMove(true, 1);
			});

			// These are the click and hover events for the features
			pluginData.featuresContainer.children("div").click(function () {
				var position = $(this).data('position');
				if (position == 1) {
					var url=$(this).find("a").attr("href");
					console.log (url);
					window.open(url, "_self");
				} else if (position == 2) {
					initiateMove(true, 1);
				} else if (position == pluginData.totalFeatureCount) {
					initiateMove(false, 1);
				}
			}).mouseover(function () {
				if (pluginData.currentlyMoving == false) {
					var position = $(this).data('position');
					if (position == 2 || position == pluginData.totalFeatureCount) {
						$(this).css("opacity", 0.8);
					}
				}
			}).mouseout(function () {
				if (pluginData.currentlyMoving == false) {
					var position = $(this).data('position');
					if (position == 2 || position == pluginData.totalFeatureCount) {
						$(this).css("opacity", 0.5);
					}
				}
			});

			// Add event listener to all clicks within the features container
			// This is done to disable any links that aren't within the center feature
			$("a", pluginData.containerIDTag).live("click", function (event) {
				// travel up to the container
				var $parents = $(this).parentsUntil(pluginData.containerIDTag);
				// now check each of the feature divs within it
				$parents.each(function () {
					var position = $(this).data('position');

					// if there are more than just feature divs within the container, they will
					// not have a position and it may come back as undefined. Throw these out
					if (position != undefined) {
						// if any of the links on a feature OTHER THAN the center feature were clicked,
						// initiate a carousel move but then throw the link action away
						// if the position WAS the center (i.e. 1), then do nothing and let the link pass
						/*if (position != 1) {
							if (position == pluginData.totalFeatureCount) {
								initiateMove(false,1);
							} else if (position == 2) {
								initiateMove(true,1);
							}
							event.preventDefault();
							return false;
						}*/
					}
				});
			});

			$(".blip").live("click", function () {
				// grab the position # that was clicked
				var goTo = $(this).attr("id").substring(5);
				// find out where that feature # actually is in the carousel right now
				var whereIsIt = pluginData.featuresContainer.children("div").eq(goTo - 1).data('position');
				// which feature # is currently in the center
				var currentlyAt = pluginData.currentCenterNum;
				// if the blip was clicked for the current center feature, do nothing
				if (goTo != currentlyAt) {
					// find the shortest distance to move the carousel
					var shortest = findShortestDistance(1, whereIsIt);
					// initiate a move in that direction with given number of rotations
					if (shortest < 0) {
						initiateMove(false, (shortest * -1));
					} else {
						initiateMove(true, shortest);
					}
				}

			});
		});
	};

	$.fn.featureCarousel.defaults = {
		// If zero, take original width and height of image
		// If between 0 and 1, multiply by original width and height (to get smaller size)
		// If greater than one, use in place of original pixel dimensions
		largeFeatureWidth: 0,
		largeFeatureHeight: 0,
		smallFeatureWidth: .5,
		smallFeatureHeight: .5,
		// how much to pad the top of the carousel
		topPadding: 0,
		// spacing between the sides of the container (pixels)
		sidePadding: 30,
		// the additional offset to pad the side features from the top of the carousel
		smallFeatureOffset: 5,
		// indicates which feature to start the carousel at
		startingFeature: 2,
		// speed in milliseconds it takes to rotate the carousel
		carouselSpeed: 1000,
		// time in milliseconds to set interval to autorotate the carousel
		// set to zero to disable it, negative to go left
		autoPlay: 0,
		// set to true to enable the creation of blips to indicate how many
		// features there are
		counterStyle: 1,
		// true to preload all images in the carousel before displaying anything
		preload: true,
		// Will only display this many features in the carousel
		// set to zero to disable
		displayCutoff: 0,
		// an easing can be specified for the animation of the carousel
		animationEasing: 'swing'
	};

})(jQuery);
