/**
 * MarcArea
 * Yet another Kemar joint (http://marcarea.com/)
 *
 */
(function(){

	$(document).ready(function(){
		$('#quote').quotify(quotes);
		$('.ertl').unobfuscate();
		$('#q').suggest();
		$('#t').tweetSuggest();
		$('#time-remaining').countdown();
		$('#comment-form label:visible').inFieldLabels();
		$('#contact-form label:visible').inFieldLabels();
		$('#portfolio').makeFolioMagic();
		// $('#hp-photo').slideHomePics();
		// $('#freelance-nav').switchBlock( $('.block') ); //partie freelance pas encore en ligne
	});

	$(window).load(function(){
		// Scroll to the top baby
		$('#top-link').click(function(ev) {
			$('html,body').animate({scrollTop:0}, 'slow', function(){
				$('a:first').focus();
			});
			ev.preventDefault();
		});
		$('#top').hide();
		// Display 'To the top' link
		if ( document.documentElement.scrollHeight > document.documentElement.clientHeight ) { $('#top').show(); };

		// on scroll jusqu'au form en cas d'erreur
		var comment_form = $('#comment-form');

		if ( $('.error',comment_form).length ) {
			$('html,body').animate( {scrollTop: comment_form.offset().top }, 'slow' );
		};

		if ( $('#comment-preview',comment_form).length ) {
			$('html,body').animate( {scrollTop: $('#comment-preview',comment_form).offset().top }, 'slow' );
		};

	});

})();

// jQuery.fn.switchBlock = function(blocks) {
// 	var nav_container = this;
// 	if (nav_container.length) {
// 		var links = $('a',nav_container);
// 		blocks.hide();
// 		$( blocks.get(0) ).show();
// 		links.click(function(e){
// 			links.removeClass('here');
// 			blocks.hide();
// 			$('#'+this.href.replace(/^http.*#/,'')).show();
// 			$(this).addClass('here');
// 			e.preventDefault();
// 		});
// 	};
// 	return this;
// };

jQuery.fn.countdown = function() {
	var countdown_container = $(this);
	if (countdown_container.length) {

		var days = $('#time-remaining-days');
		var hour = $('#time-remaining-hours');
		var mins = $('#time-remaining-mins');
		var secs = $('#time-remaining-secs');

		// days.css({'color':'#282928'});
		// hour.css({'color':'#282928'});
		// mins.css({'color':'#282928'});
		// secs.css({'color':'#282928'});

		var now = new Date();

		var closing_date_array = countdown_container.attr('title').split(',');//2010,4,25,23,18,08 => Y,n,j,G,i,s
		var closing_date = new Date(
			closing_date_array[0],		//year
			closing_date_array[1]-1,	//month 0-11
			closing_date_array[2],		//date = day 1-31
			closing_date_array[3],		//hour 0-23
			closing_date_array[4],		//minute 0-59
			closing_date_array[5]		//second 0-59
		);

		var milliseconds_remaining = closing_date.getTime() - now.getTime();

		doCountDown(milliseconds_remaining);

		countdown_container.removeAttr('title');

	};

	return this;

	function doCountDown(ms) {

		// http://stackoverflow.com/questions/175554/how-to-convert-milliseconds-into-human-readable-form
		// http://www.littlewebthings.com/2010/02/jquery-countdown-script/

		var cur_ms = ms;

		var ms = ms/1000;
		var seconds_remaining = parseInt(ms%60,10);
		ms /= 60;
		var minutes_remaining = parseInt(ms%60,10);
		ms /= 60;
		var hours_remaining = parseInt(ms%24,10);
		ms /= 24;
		var days_remaining = parseInt(ms,10);

		days.html( days_remaining    + ' jour'    + (days_remaining   <=1 ? '' : 's') );
		hour.html( hours_remaining   + ' heure'   + (hours_remaining  <=1 ? '' : 's') );
		mins.html( minutes_remaining + ' minute'  + (minutes_remaining<=1 ? '' : 's') );
		secs.html( seconds_remaining + ' seconde' + (seconds_remaining<=1 ? '' : 's') );

		if (ms>0) {
			setTimeout(function(){ doCountDown(cur_ms-1000); }, 1000);
		} else {
			$('#comment-form').hide('fast');
		};

	};

};

jQuery.fn.tweetSuggest = function() {

	var keywords_input = this;

	if (keywords_input.length) {

		var result_list = $('#tweets-list');
		var cache = result_list.html();
		var tweets_count = $('#tweets-count');
		var tweets_count_cache = tweets_count.html();
		var ajax_loader = $('#twitter-ajax-loader');

		var json_url = keywords_input.attr('alt');
		keywords_input.removeAttr('alt');

		var json_data = undefined;

		keywords_input
		// .focus(function(){
		// 	if (json_data===undefined) {
		// 		$.getJSON(json_url, function(data,textStatus) {
		// 			json_data = data;
		// 		});
		// 	};
		// })
		.blur(function(){
			if ($(this).val().length===0) {
				tweets_count.html(tweets_count_cache);
				result_list.html(cache);
			};
		})
		.ajaxStart(function() {
			ajax_loader.show();
		})
		.ajaxStop(function() {
			ajax_loader.hide();
		})
		.keyup(init)
		.attr('autocomplete','off');//get rid of the annoying autocomplete in Firefox

		$('#twitter-search-form').submit(function(e){
			e.preventDefault();
		});

		if ( location.hash.length>0 ) {
			$.getJSON(json_url, function(data,textStatus) {
				json_data = data;
				var location_hash = unescape(location.hash.replace('#',''));
				keywords_input.val( location_hash )
				searchTweet( location_hash );
			});
		};

	};
    
	return this;

	function init(event) {
		var input = keywords_input.val();
		// on charge le JSON une seule fois au 1er focus sur l'input de recherche si au moins 1 caractère est saisi dans le champ de recherche
		if (input.length>0 && input!=='' && json_data===undefined) {
			$.getJSON(json_url, function(data,textStatus) {
				json_data = data;
				searchTweet(input);
			});
		};
		if (json_data===undefined) { return; };
		if (input==='') { return endProcess(); };
		if (event.keyCode == 27) { keywords_input.val(''); return endProcess(); };//esc
		searchTweet(input);
	};

	function endProcess() {
		location.hash = '';
		tweets_count.html(tweets_count_cache);
		result_list.html(cache);
		return false;
	};

	function searchTweet(input) {

		var raw_input = input;
		input = input.replace(/'/g,"\\'").replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
		query = "$[?t~'*" + input + "*'][0:150]";//search in t property, case insensitive 'contains'
		var results = JSONQuery(query,json_data);

		if ( results.length ) {
			result_list.removeHighlight();
			var content = '';
			for (var i=0, len=results.length; i<len; i++) {
				var title = results[i].t;
				// http://snippets.dzone.com/posts/show/452
				// make it global with /g
				var url_match = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/g;
				title = title.replace(url_match,'<a href="$1">$1</a>');
				var url = 'http://twitter.com/_kemar/statuses/' + results[i].id;
				content += '<li><span>' + title + ' <a href="' + url + '">#</a></span></li>';
			};
			tweets_count.html(results.length);// affiche le nb de résultats
			result_list.html(content).highlight(raw_input);
			location.hash = escape(raw_input);
		} else {
			result_list.html('<li>Pas de résultat</li>');
		};

	};

};

jQuery.fn.suggest = function() {

	var keywords_input = this;

	if (keywords_input.length) {

		var json_url = keywords_input.attr('alt');
		keywords_input.removeAttr('alt');

		var json_data = undefined;

		// on charge le JSON une seule fois au 1er focus sur l'input de recherche
		keywords_input.focus(function(){
			if (json_data===undefined) {
				$.getJSON(json_url, function(data,textStatus) {
					json_data = data;
				});
			};
		});
		keywords_input.blur(function(){ setTimeout(function(){ $('#suggest').hide(100); }, 500 ); });
		keywords_input.keyup(init);
		keywords_input.attr('autocomplete','off');//get rid of the annoying autocomplete in Firefox
	};
    
	return this;
    
	function init(event) {

		if (json_data===undefined) { return; };

		// on récupère tout le texte saisi
		var input = $.trim($(keywords_input).val());
		if (input==='' || input==='?') { return endProcess(); };//on match le `?` en attendant un fix dans JSONQuery, flemme

		// on arrête si on detecte la touche ESC, BACK, LEFT ou RIGHT
		if (event.keyCode == 27) { return endProcess(); };//esc

		if (/^(37|39)$/.test(event.keyCode)) { return; };//left, right

		// sinon on peut construire le conteneur des suggestions
		buildSuggestionBox( keywords_input );

		// si on a quelquechose, on arrête si on detecte la touche DOWN, UP ou ENTER => on peut choisir au clavier
		if (event.keyCode == 40) { selectNextResult(); return; };//down
		if (event.keyCode == 38) { selectPrevResult(); return; };//up

		if (event.keyCode == 13) {//enter
			if ( $('#suggest li.selected').length ) {
				goToPost();
				keywords_input.keypress(function(e){
					e.preventDefault();
				});
			};
		};

		// sinon on cherche des suggestions en limitant le nombre de requetes
		getSuggestions(input);
	};

	function endProcess() {
		$('#suggest').hide();
		return false;
	};
    
	// Insere le conteneur (ul#suggest) de la liste de suggestions
	function buildSuggestionBox(keywords_input) {
		if (!$('#suggest').length) {
			var input = jQuery(keywords_input);// l'input de saisi
			var suggestion_box = $('<ul></ul>');
			suggestion_box.attr('id','suggest').hide();
			input.parent().append(suggestion_box);
		};
	};

	// on parse le json
	function getSuggestions(input) {
		var suggestion_box = $('#suggest'), content = '';
		var raw_input = input;
		var input = input.replace(/'/g,"\\'");
		query = "$[?title~'*" + input + "*'][0:6]";//search in name property, case insensitive 'contains'
		var results = JSONQuery(query,json_data);
		if ( results.length ) {
			for (var i=0, len=results.length; i<len; i++) {
				var title = results[i].title.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
				var year = results[i].year;
				var url = results[i].url;
				content += '<li><a href="' + url + '">' + title + ' <em>(' + year + ')</em>' + '</a></li>'
			};
			suggestion_box.html(content).show().highlight(raw_input);
		} else {
			suggestion_box.hide();
		};
	};

	// focus sur le prochain résultat de la liste
	function selectNextResult(){
		if ( $('#suggest li.selected').next().length ) {
			$('#suggest li.selected').removeClass('selected').next().addClass('selected');
			return;
		} else {
			$('#suggest li').removeClass('selected');
			$('#suggest li:first').addClass('selected');
			return;
		};
	};

	// focus sur le résultat précédent de la liste
	function selectPrevResult(){
		if ( $('#suggest li.selected').prev().length ) {
			$('#suggest li.selected').removeClass('selected').prev().addClass('selected');
			return;
		} else {
			$('#suggest li').removeClass('selected');
			return;
		};
	};

	// focus sur le résultat précédent de la liste
	function goToPost(){
		if ( $('#suggest li.selected').length ) {
			window.location = $('#suggest li.selected a').attr('href');
		};
	};

};

jQuery.fn.inFieldLabels = function() {

	var labels = this;

	if (labels.length) {
		labels.each(function() {
			var label = $(this);
			label
				.addClass('infield')
				.data('displayed',true);
			var f = $(this).next('input, textarea');
			if ( f.val() ) {
				label.hide().data('displayed',false)
			};
			f.focus(function() {
				hideOnFocus(label,$(this));
			}).blur(function() {
				showOnBlur(label,$(this));
			});
		});
	};

	function hideOnFocus(label,form) {
		if (!form.val() || form.val()==='') {
			label.data('displayed',true).show().css({'opacity':'0.5'});
		};
		form.keyup(function(e){
			if (label.data('displayed') && $(this).val()) {
				label.data('displayed',false).hide();
			};
			if (!form.val() || form.val()==='') {
				label.data('displayed',true).show().css({'opacity':'0.5'});
			};
		});
	};

	function showOnBlur(label,form) {
		if (form.val()==='') {
			label.data('displayed',true).show().css({'opacity':'1'});
		};
	};

	return this;

};

jQuery.fn.quotify = function(quotes) {

	var container = this;

	if (container.length) {
		var len = quotes.length - 1;
		var rand = randNum(len);
		var quote_container = $('cite',container);
		$('p',container).prepend('<a id="quote-reload" href="#">New quote</a>');
		var author_container = $('p span',container);
		newQuote( quotes[rand] );
		$('#quote-reload').bind('click',function(e){
			rand = randNum(len);
			newQuote( quotes[rand] );
			e.preventDefault();
		});
	};

	function randNum(len) {
		return Math.floor(Math.random()*(len+1));
	};

	function newQuote(quote) {
		quote_container.text('"' + quote.quote + '"');
		if (quote.url) {
			author_container.html('-- <a href="' + quote.url + '">' + quote.author + '</a>');
		} else {
			author_container.text('-- ' + quote.author);
		};
	};

	return this;

};

jQuery.fn.unobfuscate = function() {

	var elements = this;

	if (elements.length) {
		elements.each(function(i) {
			var reversed = $(this).text().split('').reverse().join('');
			if (this.nodeName.toUpperCase()==='LI') {
				$(this).wrap('<a href="mailto:'+ reversed +'"></a>')
			} else if (this.nodeName.toUpperCase()==='A') {
				var href = 'mailto:' + reversed;
				$(this).attr('href',href);
			};
		});
	};

	return this;

};

jQuery.fn.makeFolioMagic = function() {

	var portfolio = $(this);

	if (portfolio.length) {

		var main_wrapper = $('#portfolio-item-wrapper');
		var slide_up = $('<a id="slide-up" href="#">Slide up</a>').css('outline',0);
		var slide_down = $('<a id="slide-down" href="#">Slide down</a>').css('outline',0);
		var items = $('.portfolio-item', portfolio);

		var ready_to_scroll = true;
		var ready_to_fade = true;
		var current_item = undefined;
		var cur_pos = 0;
		var item_height = 304;
		var max_height = item_height * items.length;

		var current_pic_index = 0;

		var photos_containers = $('.portfolio-pics',items);
		photos_containers.each(function(){
			initPics(this);
		});

		init();
		displayControl();

		slide_up.bind('click',function(e){
			if (ready_to_scroll) {
				ready_to_scroll = false;
				slideUp();
			};
			e.preventDefault();
		});
		slide_down.bind('click',function(e){
			if (ready_to_scroll) {
				ready_to_scroll = false;
				slideDown();
			};
			e.preventDefault();
		});
		$('#portfolio-nav a').click(function(e){
			if (ready_to_scroll) {
				var item_to_display = $('#p-'+this.href.replace(/^http.*#/,''));
				if (item_to_display.length) {
					$('#portfolio-nav a').removeClass('current');
					$(this).addClass('current');
					ready_to_scroll = false;
					current_item = setCurrentItem(item_to_display);
					var pos = (item_to_display.index()) * item_height;
					slideTo(-pos);
					displayControl();
				};
			};
		});
		$(document).bind('keydown',function(e){
			if (e.keyCode===40 || e.keyCode===38) {
				e.preventDefault();
			};
			if (e.keyCode===38 && ready_to_scroll) {
				ready_to_scroll = false;
				slideUp();
			};
			if (e.keyCode===40 && ready_to_scroll) {
				ready_to_scroll = false;
				slideDown();
			};
			if (e.keyCode===39) {//next
				// e.preventDefault();
				showNextPic();
			};
			if (e.keyCode===37) {//next
				// e.preventDefault();
				showPrevPic();
			};
		});

		$('a.slide-right-small').click(function(e){
			showNextPic();
			e.preventDefault();
		});

		$('a.slide-left-small').click(function(e){
			showPrevPic();
			e.preventDefault();
		});

	};

	return this;

	function init() {
		portfolio.css({ 'height': item_height+'px' });
		main_wrapper.css({ 'position': 'absolute', 'top': 0, 'left': 0 });
		portfolio.before(slide_up);
		portfolio.after(slide_down);

		$('#content').append('<div class="keyboard">Use The Keyboard, Luke</div>');
		
		// build nav
		var nav = $('<p id="portfolio-nav"></p>');
		var nav_content = '';
		items.each(function(i){
			nav_content += '<a href="#' + this.id.replace('p-','') + '">' + (i+1) + '</a>';
		});
		$('#content').append(nav.html(nav_content))

		// go to specific
		var l = location.toString();
		var hash = undefined;
		if (l.indexOf('#')>0) { hash = l.replace(/^http.*#/,''); };
		if (hash) {
			var item_to_display = $('#p-'+hash);
			if (item_to_display.length) {
				current_item = setCurrentItem(item_to_display);
				var pos = (item_to_display.index()) * item_height;
				slideTo(-pos);
			};
		} else {
			current_item = setCurrentItem( $(items.get(0)) );
			location.hash = current_item.attr('id').replace('p-','');
			highlightCurrentNavItem();
		};

	};

	function setCurrentItem(el) {
		items.removeClass('current');
		el.addClass('current');
		
		$('a', items).attr('tabindex', -1);
		$('a', el).removeAttr('tabindex');

		return el;
	};

	function slideUp() {
		cur_pos = main_wrapper.css('top').match(/^-?\d+/)[0];
		var new_pos = Number(cur_pos) - item_height;
		if (-new_pos===max_height) {
			ready_to_scroll = true;
		} else {
			slideTo(new_pos);
		};
		if (current_item.next('.portfolio-item').length) {
			current_item = setCurrentItem( current_item.next('.portfolio-item') );
		};
		displayControl();
	};

	function slideDown() {
		cur_pos = main_wrapper.css('top').match(/^-?\d+/)[0];
		var new_pos = Number(cur_pos) + item_height;
		if (new_pos>0) {
			ready_to_scroll = true;
		} else {
			slideTo(new_pos);
		};
		if (current_item.prev('.portfolio-item').length) {
			current_item = setCurrentItem( current_item.prev('.portfolio-item') );
		};
		displayControl();
	};

	function slideTo(pos) {
		main_wrapper.animate({ top: pos+'px' }, 'slow', function() {
			location.hash = current_item.attr('id').replace('p-','');
			highlightCurrentNavItem();
			ready_to_scroll = true;
		});
		cur_pos = pos;
	};

	function highlightCurrentNavItem() {
		$('#portfolio-nav a').removeClass('current');
		$($('#portfolio-nav a').get(current_item.index())).addClass('current');
	};

	function displayControl() {
		if (-cur_pos+item_height>=max_height) {
			slide_up.animate( {'opacity':0.6}, 'fast' ).addClass('deactivated');
		} else {
			slide_up.animate( {'opacity':1}, 'fast' ).removeClass('deactivated');
		};
		if (cur_pos>=0) {
			slide_down.animate( {'opacity':0.6}, 'fast' ).addClass('deactivated');
		} else {
			slide_down.animate( {'opacity':1}, 'fast' ).removeClass('deactivated');
		};
	};

	function initPics(photos_container) {

		var photos_container = $(photos_container);

		var pics = $('img',photos_container).hide();
		if (pics.length>1) {

			var prev = $('<a class="slide-left-small" href="#">&lt;</a>').css('outline',0).attr('tabindex', -1);
			var next = $('<a class="slide-right-small" href="#">&lt;</a>').css('outline',0).attr('tabindex', -1);

			photos_container.append(prev);
			photos_container.append(next);

			var first_pic = $(pics.get(0)).addClass('visible').show();

		};
	};

	function showNextPic(pic_to_hide,pic_to_show) {
		if (ready_to_fade) {
			var pics = $('.portfolio-pics img',current_item);
			if (pics.length>1) {
				ready_to_fade = false;
				var pic_to_hide = $('.portfolio-pics img.visible',current_item);
				var pic_to_show = $(pics.get(pic_to_hide.index()+1));
				if (!pic_to_show.length) {
					pic_to_show = $(pics.get(0));
				};
				switchPic(pic_to_hide,pic_to_show);
			};
		};
	};

	function showPrevPic(pic_to_hide,pic_to_show) {
		if (ready_to_fade) {
			var pics = $('.portfolio-pics img',current_item);
			if (pics.length>1) {
				ready_to_fade = false;
				var pic_to_hide = $('.portfolio-pics img.visible',current_item);
				var pic_to_show = $(pics.get(pic_to_hide.index()-1));
				switchPic(pic_to_hide,pic_to_show);
			};
		};
	};

	function switchPic(pic_to_hide,pic_to_show) {
		pic_to_show.css('z-index', 10).addClass('visible').show();
		pic_to_hide.css({ 'z-index': 100, 'opacity': 1 }).animate({'opacity':0}, 500, function(){
			$(this).removeClass('visible').hide().css('opacity', 1);
			ready_to_fade = true;
		});
	};

};

// jQuery.fn.slideHomePics = function() {
// 
// 	var container = this;
// 
// 	if (container.length) {
// 
// 		// set global vars
// 		var items = $('.hp-photo-item', container);
// 		var sliding_block = $('#hp-photo-wrapper');
// 		container.append('<a id="slide-left" href="#">&lt;</a><a id="slide-right" href="#">&gt;</a>');
// 		var left_btn = $('#slide-left');
// 		var right_btn = $('#slide-right');
// 
// 		var cur_pos = 0;
// 		var min_width = 620;//width of 1 pic
// 		var max_width = (items.length*min_width);
// 		var max_left_pos = -(max_width-min_width);
// 		var ready_to_scroll = true;
// 
// 		init();
// 		displayControl();
// 
// 		container.bind('mouseenter',function(e){
// 			displayControl();
// 			e.preventDefault();
// 		});
// 		container.bind('mouseleave',function(e){
// 			hideControl();
// 			e.preventDefault();
// 		});
// 
// 		left_btn.bind('click',function(e){
// 			if (ready_to_scroll) {
// 				ready_to_scroll = false;
// 				slideLeft();
// 			};
// 			e.preventDefault();
// 		});
// 		right_btn.bind('click',function(e){
// 			if (ready_to_scroll) {
// 				ready_to_scroll = false;
// 				slideRight();
// 			};
// 			e.preventDefault();
// 		});
// 
// 		$(document).bind('keydown',function(e){
// 			if (e.keyCode===37 && ready_to_scroll) {
// 				// e.preventDefault();
// 				ready_to_scroll = false;
// 				slideLeft();
// 			};
// 			if (e.keyCode===39 && ready_to_scroll) {
// 				// e.preventDefault();
// 				ready_to_scroll = false;
// 				slideRight();
// 			};
// 			if (e.keyCode===27) {
// 				hideControl();
// 			};
// 		});
// 
// 	};
// 
// 	return this;
// 
// 	function init() {
// 
// 		// prevent default focus
// 		left_btn.css({ 'outline': 0, 'left': '-30px' }).attr('tabindex', -1);
// 		right_btn.css({ 'outline': 0, 'right': '-30px' }).attr('tabindex', -1);
// 
// 		// float items => get all items on a single line
// 		items.css({
// 			'position': 'static',
// 			'text-align': 'right',
// 			'float': 'left',
// 			'display': 'block'
// 		});
// 
// 		// set sliding_block width
// 		sliding_block.css({
// 			'width': max_width+'px'
// 		});
// 
// 	};
// 
// 	function slideLeft() {
// 		cur_pos = sliding_block.css('left').match(/^-?\d+/)[0];
// 		var new_pos = Number(cur_pos) - min_width;
// 		cur_pos = new_pos;
// 		if (new_pos >= max_left_pos) {
// 			sliding_block.animate({ left: new_pos+'px' }, 'slow', function() {
// 				ready_to_scroll = true;
// 			});
// 		} else {
// 			ready_to_scroll = true;
// 		};
// 		displayControl();
// 	};
// 
// 	function slideRight() {
// 		cur_pos = sliding_block.css('left').match(/^-?\d+/)[0];
// 		var new_pos = Number(cur_pos) + min_width;
// 		cur_pos = new_pos;
// 		if (new_pos<=0) {
// 			sliding_block.animate({ left: new_pos+'px' }, 'slow', function() {
// 				ready_to_scroll = true;
// 			});
// 		} else {
// 			ready_to_scroll = true;
// 		};
// 		displayControl();
// 	};
// 
// 	function displayControl() {
// 		if (cur_pos===max_left_pos) {
// 			// left_btn.hide();
// 			left_btn.animate( {'left':'-30px'}, 'fast' );
// 		} else if (cur_pos>max_left_pos) {
// 			// left_btn.show();
// 			left_btn.animate( {'left':0}, 'fast' );
// 		};
// 		if (cur_pos===0) {
// 			// right_btn.hide();
// 			right_btn.animate( {'right':'-30px'}, 'fast' );
// 		} else if (cur_pos<min_width) {
// 			// right_btn.show();
// 			right_btn.animate( {'right':0}, 'fast' );
// 		};
// 	};
// 
// 	function hideControl() {
// 		left_btn.animate( {'left':'-30px'}, 'fast' );
// 		right_btn.animate( {'right':'-30px'}, 'fast' );
// 	};
// 
// };

var quotes = [
        {
            "quote": "On se voit demain pour parler de ton suicide professionnel",
            "author": "Manager from teh hell",
            "url": ""
        },
        {
            "quote": "Cuba quiero bailar la salsa",
            "author": "Gibson Brothers - Cuba 1978",
            "url": "http://www.youtube.com/watch?v=Wp9ecwfjbUU"
        },
        {
            "quote": "If you're good at something, never do it for free.",
            "author": "The Joker",
            "url": "http://www.youtube.com/watch?v=uYMnAUGFuG0"
        },
        {
            "quote": "Look at This Fucking Graph, It's Fucking Going Upwards",
            "author": "Someone from teh internet",
            "url": "http://imgur.com/DzZdf.jpg"
        },
        {
            "quote": "Sup dawg, we heard you like kernels, so we put a kernel in your micro-kernel (so you can Mach while you BSD)",
            "author": "Someone from teh internet",
            "url": ""
        },
        {
            "quote": "w00t! i just pwn3d that n00b!",
            "author": "Someone from teh irc",
            "url": ""
        },
        {
            "quote": "Where's all the fucking water coming from?",
            "author": "Captain of the Titanic - 1912",
            "url": "http://justin.justnet.com.au/rudestuff/uses-of-the-word-fuck.html"
        },
        {
            "quote": "Don't hate the ripper, hate the game",
            "author": "Someone from teh internet",
            "url": "http://www.tuaw.com/2006/10/31/dont-hate-the-ripper-hate-the-game/"
        },
        {
            "quote": "Dude, Sam Jackson mothafuckin' hates me!",
            "author": "Someone from teh internet",
            "url": ""
        },
        {
            "quote": "Shit happens when you party naked",
            "author": "Thurman",
            "url": ""
        },
        {
            "quote": "Don't Copy That Floppy",
            "author": "Oppressor from teh HADOPI",
            "url": "http://www.youtube.com/watch?v=up863eQKGUI"
        },
        {
            "quote": "Personnelement, c'est pas Dieu qui me dérange, c'est son putain de fan club",
            "author": "Someone from teh internet",
            "url": ""
        },
        {
            "quote": "Quand tout le reste a échoué, lisez le mode d'emploi.",
            "author": "Someone using LINUX",
            "url": ""
        },
        {
            "quote": "Told you so. Linux rulez teh internets",
            "author": "Someone high",
            "url": ""
        },
        {
            "quote": "Ta mère est un ingénieur FrontPage",
            "author": "Un développeur web en colère",
            "url": ""
        },
        {
            "quote": "Hé mec, mon nom à moi C'est Hubert Valéry Patrick Stanislas Duc de Montmorency",
            "author": "Les inconnus",
            "url": "http://www.youtube.com/watch?v=0uHikQqc4ik"
        },
        {
            "quote": "Jesus saves, but only Buddha makes incremental backups",
            "author": "MrZebra",
            "url": "http://stackoverflow.com/questions/234075/what-is-your-best-programmer-joke/234159#comments-234159"
        },
        {
            "quote": "Yeah, whatever, motherfucker",
            "author": "Pinky Chauffeur, Next Friday",
            "url": "http://www.youtube.com/watch?v=HkqXgn50CjM"
        },
        {
            "quote": "Vengeance blackens the soul, Bruce",
            "author": "Alfred, Batman: Mask of the Phantasm",
            "url": "http://www.imdb.com/title/tt0106364/quotes?qt0203936"
        },
        {
            "quote": "This goes out to my Brooklyn crew represtin all the freaky bitches, fuck 'em all day and fuck 'em all night, we don't love these hoes",
            "author": "The Notorious B.I.G. - Nasty Boy",
            "url": "http://www.youtube.com/watch?v=Wx8uI6swbzE"
        },
        {
            "quote": "I don't know why the fuck I'm fuckin wit you",
            "author": "Slum Village - I Don't Know",
            "url": "http://www.youtube.com/watch?v=rXd5ZXTjStA"
        },
        {
            "quote": "Aiyyo, I got a slight problem, I smoke weed too much",
            "author": "Redman - Smoke Buddah",
            "url": "http://www.youtube.com/watch?v=4LDpgkoRtL8"
        },
        {
            "quote": "I done told you boy I'm a soldier boy, I got no choice but to be a rider",
            "author": "G-Unit - Rider Pt.2",
            "url": "http://www.youtube.com/watch?v=H0aAEchtPBQ"
        },
        
        {
            "quote": "Faire d'l'argent avant de mourir le dilemme d'la race humaine",
            "author": "Rockin Squat, Illegal Mixtape",
            "url": ""
        },
        {
            "quote": "Life As A Shorty Shouldn't Be So Rough",
            "author": "Wu-Tang Clan - C.R.E.A.M.",
            "url": "http://www.youtube.com/watch?v=e69laCvKxEw"
        },
        {
            "quote": "What would you do... if the vicious enemy suddenly started comin at you... armed to the teeth, and ready to kill you?",
            "author": "Chorus from Da Enemy - D.I.T.C.",
            "url": "http://www.youtube.com/watch?v=ObuP9mHWOdw"
        },
        {
            "quote": "Kilo is SO going to be a #1 hit",
            "author": "Un fan de Ghostface",
            "url": ""
        },
        {
            "quote": "We don't give a fuck when we smoked out",
            "author": "Redman - Whateva Man",
            "url": "http://www.youtube.com/watch?v=UXI0S-5ToPs"
        },
        {
            "quote": "Thats my word, I'm mothafuckin' stressed - It seems like life's tryin' to put me through a test",
            "author": "Blaq Poet - The Heat is On",
            "url": "http://www.youtube.com/watch?v=SUf7zr690q8"
        },
        {
            "quote": "I'm writin my name in graffiti on the wall - So when I'm on tour I represent the hardcore - I'm taggin up your blackbook sure, I'm out for fame",
            "author": "KRS One - Out For Fame",
            "url": "http://www.youtube.com/watch?v=hpCnhtY2Pp8"
        },
        {
            "quote": "They rally round tha family! With a pocket full of shells",
            "author": "RATM",
            "url": "http://www.ratm.net/lyrics/bull.html"
        },
        {
            "quote": "Who the fuck is this? Pagin me at 5:46 in the mornin",
            "author": "Notorious B.I.G. - Warning",
            "url": "http://www.youtube.com/watch?v=QQlmLf67m18"
        },
        {
            "quote": "Motherfucker don't you know I'm stranded on the row? Beeyatch",
            "author": "Kurupt - Puffin on Blunts and Drankin Tanqueray",
            "url": "http://www.youtube.com/watch?v=XSY8waSPDTk"
        },
        {
            "quote": "If you not gonna take care of business... STOP TAKING UP SPAAACE",
            "author": "Superb & Solomon Childs - Take Up Space",
            "url": "http://www.youtube.com/watch?v=jNiRdZyHuvo"
        },
        {
            "quote": "You know you can't fuck with my motherfuckin DJ - That's my homey and we call him Warren G",
            "author": "Snoop - Stranded On Death Row",
            "url": "http://www.youtube.com/watch?v=h-UkjmkHfW4"
        },
        {
            "quote": "Toujours le Filet'O'Fish au Mc Do, bitches",
            "author": "Sefyu - Molotov 4",
            "url": "http://www.youtube.com/watch?v=mcZQHPvcn5M"
        },
        {
            "quote": "Oooweeee the beat BANGS",
            "author": "Someone from teh YouTube",
            "url": ""
        },
        {
            "quote": "I work the angles sharp and precise, Dilated Peoples so you better build twice",
            "author": "Dilated Peoples - Work The Angles",
            "url": "http://www.youtube.com/watch?v=a2kYVCl8Kh0"
        },
        {
            "quote": "My life depends upon my gun and my gun spells hope in the land where the rope and the colt are king",
            "author": "Scott Walker - The Rope And The Colt",
            "url": "http://www.youtube.com/watch?v=1U5WlMWiDSY"
        },
        {
            "quote": "Yo, this way to savings! Save your dollars bills, yo!",
            "author": "Breaking Bad s01e05",
            "url": ""
        },
        {
            "quote": "I'm an example of western civilization's decline. I'm a loner, a rebel, samurai solo",
            "author": "Bun B - Choose Your Side",
            "url": "http://www.youtube.com/watch?v=oCdvPp5OP5o"
        }
];

/*

highlight v3

Highlights arbitrary terms.

<http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html>

MIT license.

Johann Burkard
<http://johannburkard.de>
<mailto:jb@eaio.com>

*/

jQuery.fn.highlight = function(pat) {
	function innerHighlight(node, pat) {
		var skip = 0;
		if (node.nodeType == 3) {
			var pos = node.data.toUpperCase().indexOf(pat);
			if (pos >= 0) {
				var strongnode = document.createElement('strong');
				strongnode.className = 'highlight';
				var middlebit = node.splitText(pos);
				var endbit = middlebit.splitText(pat.length);
				var middleclone = middlebit.cloneNode(true);
				strongnode.appendChild(middleclone);
				middlebit.parentNode.replaceChild(strongnode, middlebit);
				skip = 1;
			};
		} else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
			for (var i = 0; i < node.childNodes.length; ++i) {
				i += innerHighlight(node.childNodes[i], pat);
			};
		};
		return skip;
	};
	return this.each(function() {
		innerHighlight(this, pat.toUpperCase());
	});
};

jQuery.fn.removeHighlight = function() {
	return this.find("strong.highlight").each(function() {
		this.parentNode.firstChild.nodeName;
		with (this.parentNode) {
			replaceChild(this.firstChild, this);
			normalize();
		};
	}).end();
};

/*
Copyright Jason E. Smith 2008 Licensed under the Apache License, Version 2.0 (the "License");
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/


/*
* CREDITS:
* Thanks to Kris Zyp from SitePen for contributing his source for
* a standalone port of JSONQuery (from the dojox.json.query module).
*
* OVERVIEW:
* JSONQuery.js is a standalone port of the dojox.json.query module. It is intended as
* a dropin solution with zero dependencies. JSONQuery is intended to succeed and improve upon
* the JSONPath api (http://goessner.net/articles/JsonPath/) which offers rich powerful
* querying capabilities similar to those of XQuery.
*
* EXAMPLES / USAGE:
* see http://www.sitepen.com/blog/2008/07/16/jsonquery-data-querying-beyond-jsonpath/
*
*     *Ripped from original source.
*         JSONQuery(queryString,object)
        and
        JSONQuery(queryString)(object)
        always return identical results. The first one immediately evaluates, the second one returns a
        function that then evaluates the object.

      example:
        JSONQuery("foo",{foo:"bar"})
        This will return "bar".

      example:
        evaluator = JSONQuery("?foo='bar'&rating>3");
        This creates a function that finds all the objects in an array with a property
        foo that is equals to "bar" and with a rating property with a value greater
        than 3.
        evaluator([{foo:"bar",rating:4},{foo:"baz",rating:2}])
        This returns:
        {foo:"bar",rating:4}

      example:
        evaluator = JSONQuery("$[?price<15.00][\rating][0:10]");
        This finds objects in array with a price less than 15.00 and sorts then
        by rating, highest rated first, and returns the first ten items in from this
        filtered and sorted list.


  example:      
    var data = {customers:[
      {name:"Susan", purchases:29},
      {name:"Kim", purchases:150}, 
      {name:"Jake", purchases:27}
    ]};

    var results = json.JSONQuery("$.customers[?purchases > 21 & name='Jake'][\\purchases]",data);
    results 

    returns customers sorted by higest number of purchases to lowest.

*/

 (function() {
    function map(arr, fun
    /*, thisp*/
    ) {
        var len = arr.length;
        if (typeof fun != "function")
        throw new TypeError();

        var res = new Array(len);
        var thisp = arguments[2];
        for (var i = 0; i < len; i++) {
            if (i in arr)
            res[i] = fun.call(thisp, arr[i], i, arr);
        }

        return res;
    }

    function filter(arr, fun
    /*, thisp*/
    ) {
        var len = arr.length;
        if (typeof fun != "function")
        throw new TypeError();

        var res = new Array();
        var thisp = arguments[2];
        for (var i = 0; i < len; i++) {
            if (i in arr) {
                var val = arr[i];
                // in case fun mutates this
                if (fun.call(thisp, val, i, arr))
                res.push(val);
            }
        }

        return res;
    };


    function slice(obj, start, end, step) {
        // handles slice operations: [3:6:2]
        var len = obj.length,
        results = [];
        end = end || len;
        start = (start < 0) ? Math.max(0, start + len) : Math.min(len, start);
        end = (end < 0) ? Math.max(0, end + len) : Math.min(len, end);
        for (var i = start; i < end; i += step) {
            results.push(obj[i]);
        }
        return results;
    }
    function expand(obj, name) {
        // handles ..name, .*, [*], [val1,val2], [val]
        // name can be a property to search for, undefined for full recursive, or an array for picking by index
        var results = [];
        function walk(obj) {
            if (name) {
                if (name === true && !(obj instanceof Array)) {
                    //recursive object search
                    results.push(obj);
                } else if (obj[name]) {
                    // found the name, add to our results
                    results.push(obj[name]);
                }
            }
            for (var i in obj) {
                var val = obj[i];
                if (!name) {
                    // if we don't have a name we are just getting all the properties values (.* or [*])
                    results.push(val);
                } else if (val && typeof val == 'object') {

                    walk(val);
                }
            }
        }
        if (name instanceof Array) {
            // this is called when multiple items are in the brackets: [3,4,5]
            if (name.length == 1) {
                // this can happen as a result of the parser becoming confused about commas
                // in the brackets like [@.func(4,2)]. Fixing the parser would require recursive
                // analsys, very expensive, but this fixes the problem nicely.
                return obj[name[0]];
            }
            for (var i = 0; i < name.length; i++) {
                results.push(obj[name[i]]);
            }
        } else {
            // otherwise we expanding
            walk(obj);
        }
        return results;
    }

    function distinctFilter(array, callback) {
        // does the filter with removal of duplicates in O(n)
        var outArr = [];
        var primitives = {};
        for (var i = 0, l = array.length; i < l; ++i) {
            var value = array[i];
            if (callback(value, i, array)) {
                if ((typeof value == 'object') && value) {
                    // with objects we prevent duplicates with a marker property
                    if (!value.__included) {
                        value.__included = true;
                        outArr.push(value);
                    }
                } else if (!primitives[value + typeof value]) {
                    // with primitives we prevent duplicates by putting it in a map
                    primitives[value + typeof value] = true;
                    outArr.push(value);
                }
            }
        }
        for (i = 0, l = outArr.length; i < l; ++i) {
            // cleanup the marker properties
            if (outArr[i]) {
                delete outArr[i].__included;
            }
        }
        return outArr;
    }
    var JSONQuery = function(
    /*String*/
    query,
    /*Object?*/
    obj) {
        // summary:
        //     Performs a JSONQuery on the provided object and returns the results.
        //     If no object is provided (just a query), it returns a "compiled" function that evaluates objects
        //     according to the provided query.
        // query:
        //     Query string
        //   obj:
        //     Target of the JSONQuery
        //
        //  description:
        //    JSONQuery provides a comprehensive set of data querying tools including filtering,
        //    recursive search, sorting, mapping, range selection, and powerful expressions with
        //    wildcard string comparisons and various operators. JSONQuery generally supersets
        //     JSONPath and provides syntax that matches and behaves like JavaScript where
        //     possible.
        //
        //    JSONQuery evaluations begin with the provided object, which can referenced with
        //     $. From
        //     the starting object, various operators can be successively applied, each operating
        //     on the result of the last operation.
        //
        //     Supported Operators:
        //     --------------------
        //    * .property - This will return the provided property of the object, behaving exactly
        //     like JavaScript.
        //     * [expression] - This returns the property name/index defined by the evaluation of
        //     the provided expression, behaving exactly like JavaScript.
        //    * [?expression] - This will perform a filter operation on an array, returning all the
        //     items in an array that match the provided expression. This operator does not
        //    need to be in brackets, you can simply use ?expression, but since it does not
        //    have any containment, no operators can be used afterwards when used
        //     without brackets.
        //    * [^?expression] - This will perform a distinct filter operation on an array. This behaves
        //    as [?expression] except that it will remove any duplicate values/objects from the
        //    result set.
        //     * [/expression], [\expression], [/expression, /expression] - This performs a sort
        //     operation on an array, with sort based on the provide expression. Multiple comma delimited sort
        //     expressions can be provided for multiple sort orders (first being highest priority). /
        //    indicates ascending order and \ indicates descending order
        //     * [=expression] - This performs a map operation on an array, creating a new array
        //    with each item being the evaluation of the expression for each item in the source array.
        //    * [start:end:step] - This performs an array slice/range operation, returning the elements
        //    from the optional start index to the optional end index, stepping by the optional step number.
        //     * [expr,expr] - This a union operator, returning an array of all the property/index values from
        //     the evaluation of the comma delimited expressions.
        //     * .* or [*] - This returns the values of all the properties of the current object.
        //     * $ - This is the root object, If a JSONQuery expression does not being with a $,
        //     it will be auto-inserted at the beginning.
        //     * @ - This is the current object in filter, sort, and map expressions. This is generally
        //     not necessary, names are auto-converted to property references of the current object
        //     in expressions.
        //     *  ..property - Performs a recursive search for the given property name, returning
        //     an array of all values with such a property name in the current object and any subobjects
        //     * expr = expr - Performs a comparison (like JS's ==). When comparing to
        //     a string, the comparison string may contain wildcards * (matches any number of
        //     characters) and ? (matches any single character).
        //     * expr ~ expr - Performs a string comparison with case insensitivity.
        //    * ..[?expression] - This will perform a deep search filter operation on all the objects and
        //     subobjects of the current data. Rather than only searching an array, this will search
        //     property values, arrays, and their children.
        //    * $1,$2,$3, etc. - These are references to extra parameters passed to the query
        //    function or the evaluator function.
        //    * +, -, /, *, &, |, %, (, ), <, >, <=, >=, != - These operators behave just as they do
        //     in JavaScript.
        //
        //
        //
        //   |  dojox.json.query(queryString,object)
        //     and
        //   |  dojox.json.query(queryString)(object)
        //     always return identical results. The first one immediately evaluates, the second one returns a
        //     function that then evaluates the object.
        //
        //   example:
        //   |  dojox.json.query("foo",{foo:"bar"})
        //     This will return "bar".
        //
        //  example:
        //  |  evaluator = dojox.json.query("?foo='bar'&rating>3");
        //    This creates a function that finds all the objects in an array with a property
        //    foo that is equals to "bar" and with a rating property with a value greater
        //    than 3.
        //  |  evaluator([{foo:"bar",rating:4},{foo:"baz",rating:2}])
        //     This returns:
        //   |  {foo:"bar",rating:4}
        //
        //  example:
        //   |  evaluator = dojox.json.query("$[?price<15.00][\rating][0:10]");
        //      This finds objects in array with a price less than 15.00 and sorts then
        //     by rating, highest rated first, and returns the first ten items in from this
        //     filtered and sorted list.
        tokens = [];
        var depth = 0;
        var str = [];
        query = query.replace(/"(\\.|[^"\\])*"|'(\\.|[^'\\])*'|[\[\]]/g,
        function(t) {
            depth += t == '[' ? 1: t == ']' ? -1: 0;
            // keep track of bracket depth
            return (t == ']' && depth > 0) ? '`]':
            // we mark all the inner brackets as skippable
            (t.charAt(0) == '"' || t.charAt(0) == "'") ? "`" + (str.push(t) - 1) :
            // and replace all the strings
            t;
        });
        var prefix = '';
        function call(name) {
            // creates a function call and puts the expression so far in a parameter for a call
            prefix = name + "(" + prefix;
        }
        function makeRegex(t, a, b, c, d) {
            // creates a regular expression matcher for when wildcards and ignore case is used
            return str[d].match(/[\*\?]/) || c == '~' ?
            "/^" + str[d].substring(1, str[d].length - 1).replace(/\\([btnfr\\"'])|([^\w\*\?])/g, "\\$1$2").replace(/([\*\?])/g, ".$1") + (c == '~' ? '$/i': '$/') + ".test(" + a + ")":
            t;
        }
        query.replace(/(\]|\)|push|pop|shift|splice|sort|reverse)\s*\(/,
        function() {
            throw new Error("Unsafe function call");
        });

        query = query.replace(/([^<>=]=)([^=])/g, "$1=$2").
        // change the equals to comparisons
        replace(/@|(\.\s*)?[a-zA-Z\$_]+(\s*:)?/g,
        function(t) {
            return t.charAt(0) == '.' ? t:
            // leave .prop alone
            t == '@' ? "$obj":
            // the reference to the current object
            (t.match(/:|^(\$|Math|true|false|null)$/) ? "": "$obj.") + t;
            // plain names should be properties of root... unless they are a label in object initializer
        }).
        replace(/\.?\.?\[(`\]|[^\]])*\]|\?.*|\.\.([\w\$_]+)|\.\*/g,
        function(t, a, b) {
            var oper = t.match(/^\.?\.?(\[\s*\^?\?|\^?\?|\[\s*==)(.*?)\]?$/);
            // [?expr] and ?expr and [=expr and =expr
            if (oper) {
                var prefix = '';
                if (t.match(/^\./)) {
                    // recursive object search
                    call("expand");
                    prefix = ",true)";
                }
                call(oper[1].match(/\=/) ? "map": oper[1].match(/\^/) ? "distinctFilter": "filter");
                return prefix + ",function($obj){return " + oper[2] + "})";
            }
            oper = t.match(/^\[\s*([\/\\].*)\]/);
            // [/sortexpr,\sortexpr]
            if (oper) {
                // make a copy of the array and then sort it using the sorting expression
                return ".concat().sort(function(a,b){" + oper[1].replace(/\s*,?\s*([\/\\])\s*([^,\\\/]+)/g,
                function(t, a, b) {
                    return "var av= " + b.replace(/\$obj/, "a") + ",bv= " + b.replace(/\$obj/, "b") +
                    // FIXME: Should check to make sure the $obj token isn't followed by characters
                    ";if(av>bv||bv==null){return " + (a == "/" ? 1: -1) + ";}\n" +
                    "if(bv>av||av==null){return " + (a == "/" ? -1: 1) + ";}\n";
                }) + "})";
            }
            oper = t.match(/^\[(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)\]/);
            // slice [0:3]
            if (oper) {
                call("slice");
                return "," + (oper[1] || 0) + "," + (oper[2] || 0) + "," + (oper[3] || 1) + ")";
            }
            if (t.match(/^\.\.|\.\*|\[\s*\*\s*\]|,/)) {
                // ..prop and [*]
                call("expand");
                return (t.charAt(1) == '.' ?
                ",'" + b + "'":
                // ..prop
                t.match(/,/) ?
                "," + t:
                // [prop1,prop2]
                "") + ")";
                // [*]
            }
            return t;
        }).
        replace(/(\$obj\s*(\.\s*[\w_$]+\s*)*)(==|~)\s*`([0-9]+)/g, makeRegex).
        // create regex matching
        replace(/`([0-9]+)\s*(==|~)\s*(\$obj(\s*\.\s*[\w_$]+)*)/g,
        function(t, a, b, c, d) {
            // and do it for reverse =
            return makeRegex(t, c, d, b, a);
        });
        query = prefix + (query.charAt(0) == '$' ? "": "$") + query.replace(/`([0-9]+|\])/g,
        function(t, a) {
            //restore the strings
            return a == ']' ? ']': str[a];
        });
        // create a function within this scope (so it can use expand and slice)
        var executor = eval("1&&function($,$1,$2,$3,$4,$5,$6,$7,$8,$9){var $obj=$;return " + query + "}");
        for (var i = 0; i < arguments.length - 1; i++) {
            arguments[i] = arguments[i + 1];
        }
        return obj ? executor.apply(this, arguments) : executor;
    };


    if (typeof namespace == "function") {
        namespace("json::JSONQuery", JSONQuery);
    }
    else {
        window["JSONQuery"] = JSONQuery;
    }
})();

