// jQuery Plugin TimelineBrowser
// A plugin to browse through content with a timeline 
// Version 0.9.1 - 22. 12. 2011
// by Fredi Bach

(function($) {

    $.timelineBrowser = function(element, options) {

        var defaults = {
			data: {},
			cssprefix: 'timeline_browser',
			searchstring: '',
			currentyear: 'last',
			currententry: 'last',
			autoplay: true,
			autorestart: true,
			autorestartafter: 20000,
			direction: 'backwards',
			delay: 7500,
			accuracy: 100,
			activeclass: 'active',
			searchedclass: 'searched',
			fadecontent: true,
			fadespeed: 'fast',
			centering: true, 
			onChange: function() {}
        }

        var plugin = this;
		
        plugin.settings = {}

        var $element = $(element),
             element = element;

		var maxyear = undefined;
		var minyear = undefined;
		var currentyear = undefined;
		var currententry = undefined;
		var searchmode = false;
		var $yearselement = $;
		var $entrieselement = $;
		var $contentelement = $;
		var lastautoplay = 0;
		var lastactivity = 0;
		var windowhasfocus = true;
		
		$(window).focus(function() {
		    windowhasfocus = true;
		});

		$(window).blur(function() {
		    windowhasfocus = false;
		});
		
        plugin.init = function() {
            plugin.settings = $.extend({}, defaults, options);
			var s = plugin.settings;
			
			$yearselement = $element.find('#'+s.cssprefix+'_years');
			$entrieselement = $element.find('#'+s.cssprefix+'_yearentries');
			$contentelement = $element.find('#'+s.cssprefix+'_currententry');
			
			var yeartimeline = '<ul>';
			var yearcount = 0;
			$.each(s.data, function(index, value) {
				yeartimeline += '<li id="'+s.cssprefix+'_year_'+index+'">'+index+'</li>';
				yearcount++;
				if (maxyear == undefined || index > maxyear){
					maxyear = index;
				}
				if (minyear == undefined || index < minyear){
					minyear = index;
				}
			});
			yeartimeline += '</ul>';
			
			if (typeof(s.currentyear) == 'number'){
				currentyear = s.currentyear;
			} else if (s.currentyear == 'last'){
				currentyear = maxyear;
			} else {
				currentyear = minyear;
			}
			
			$yearselement.html(yeartimeline);
			$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).addClass(s.activeclass);
			
			var containerwidth = $yearselement.find('ul').width();
			var liwidth = Math.floor(containerwidth / yearcount);
			var thiswidth = 0;
			
			$yearselement.find('ul li').each( function(){
				if (s.centering){
					$(this).width(liwidth);
				}
				var y = $(this).text();
				thiswidth += liwidth;
				$(this).bind( 'click', function(){
					s.autoplay = false;
					plugin.showYear(y);
				});
			});
			
			if (s.centering){
				$yearselement.find('ul').css('margin-left', Math.floor( (containerwidth - thiswidth) / 2) );
			}
			
			plugin.createEntriesTimeline();
			
			if (typeof(s.currententry) == 'number'){
				currententry = s.currententry;
			} else if (s.currententry == 'last'){
				currententry = s.data[currentyear].length - 1;
			} else {
				currententry = 0;
			}
			
			$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
			
			$contentelement.html(s.data[currentyear][currententry].content);
			
			$element.find('#'+s.cssprefix+'_prev').bind('click', function(){
				s.autoplay = false;
				plugin.showPrev();
			});
			
			$element.find('#'+s.cssprefix+'_next').bind('click', function(){
				s.autoplay = false;
				plugin.showNext();
			});
			
			$element.find('#'+s.cssprefix+'_search input').bind('change', function(){
				plugin.searchHighlight(true);
			});
			
			$element.find('#'+s.cssprefix+'_searchreset').bind('click', function(){
				var s = plugin.settings;
				s.autoplay = false;
				$element.find('#'+s.cssprefix+'_search input').val('');
				plugin.searchHighlight();
			});
			
			$element.find('#'+s.cssprefix+'_searchreset').fadeTo('fast', 0.25);
			
			if (s.autoplay){
				lastautoplay = (new Date).getTime();
				window.setTimeout( function() { plugin.autoplayer(); }, s.accuracy);
			}
        }

		plugin.autoplayer = function(){
			var s = plugin.settings;
			if (s.autoplay){
				if ( (new Date).getTime() - lastautoplay > s.delay && windowhasfocus ){
					lastautoplay = (new Date).getTime();
					if (s.direction == 'backwards'){
						plugin.showPrev();
					} else {
						plugin.showNext();
					}
				}
				window.setTimeout( function() { plugin.autoplayer(); }, s.accuracy);
			} else {
				if (s.autorestart){
					if ( (new Date).getTime() - lastactivity > s.autorestartafter ){
						s.autoplay = true;
					}
				}
				window.setTimeout( function() { plugin.autoplayer(); }, s.accuracy);
			}
		}

		plugin.textFromHTMLString = function(htmlstring){
			var $tempdiv = jQuery('<div/>', {}).html(htmlstring);
			return $tempdiv.text();
		}
		
		plugin.play = function(){
			s.autoplay = true;
			lastautoplay = (new Date).getTime();
			window.setTimeout( function() { plugin.autoplayer(); }, s.accuracy);
		}

		plugin.searchHighlight = function(jump){
			var s = plugin.settings;
			var searchstring = $.trim($element.find('#'+s.cssprefix+'_search input').val()).toLowerCase();
			
			$yearselement.find('ul li').each( function(){
				$(this).removeClass(s.searchedclass);
			});
			$entrieselement.find('ul li').each( function(){
				$(this).removeClass(s.searchedclass);
			});
			
			if (searchstring != '' && searchstring.length > 3){
				searchmode = true;
				s.autoplay = false;
				
				$element.find('#'+s.cssprefix+'_searchreset').fadeTo('fast', 1.0);
				
				$.each(s.data, function(year, value2) {
					$.each(s.data[year], function(index, value2) {
						if (value2.title.toLowerCase().indexOf(searchstring) > -1 || plugin.textFromHTMLString(value2.content).toLowerCase().indexOf(searchstring) > -1){
							$yearselement.find('#'+s.cssprefix+'_year_'+year).addClass(s.searchedclass);
							if (currentyear == year){
								$entrieselement.find('#'+s.cssprefix+'_entry_'+index).addClass(s.searchedclass);
							}
							s.data[year][index].searched = true;
						} else {
							s.data[year][index].searched = false;
						}
					});
				});
				
				if (jump != undefined && jump){
					var lastyear = $yearselement.find("ul li."+s.searchedclass+":last").text();
					if (lastyear != undefined && lastyear != ''){
						if (lastyear == currentyear){
							var idsplit = $entrieselement.find("ul li."+s.searchedclass+":last").attr('id').split('_');
							var lastentry = idsplit[(idsplit.length-1)];
							plugin.showEntry(lastentry);
						} else {
							$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).removeClass(s.activeclass);
							currentyear = lastyear;
							$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).addClass(s.activeclass);
							plugin.createEntriesTimeline();
							
							$.each(s.data, function(year, value2) {
								$.each(s.data[year], function(index, value2) {
									if (value2.title.indexOf(searchstring) > -1 || value2.content.indexOf(searchstring) > -1){
										$entrieselement.find('#'+s.cssprefix+'_entry_'+index).addClass(s.searchedclass);
									}
								});
							});
							
							var idsplit = $entrieselement.find("ul li."+s.searchedclass+":last").attr('id').split('_');
							var lastentry = idsplit[(idsplit.length-1)];
							plugin.showEntry(lastentry);
							$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).addClass(s.activeclass);
							$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
							
						}
					}
				}
				
				s.onChange('next');
				
			} else {
				searchmode = false;
				$element.find('#'+s.cssprefix+'_searchreset').fadeTo('fast', 0.5);
			}
		}

		plugin.createEntriesTimeline = function(){
			var s = plugin.settings;
			
			var entriestimeline = '<ul>';
			$.each(s.data[currentyear], function(index, value) {
				entriestimeline += '<li id="'+s.cssprefix+'_entry_'+index+'">&nbsp;</li>';
			});
			entriestimeline += '</ul>';
			
			$entrieselement.html(entriestimeline);
			
			var containerwidth = $entrieselement.find('ul').width();
			
			var liwidth = Math.floor(containerwidth / s.data[currentyear].length);
			var thiswidth = 0;
			
			$entrieselement.find('ul li').each( function(){
				if (s.centering){
					$(this).width(liwidth);
				}
				thiswidth += liwidth;
				$(this).bind( 'click', function(){
					s.autoplay = false;
					var idsplit = $(this).attr('id').split('_');
					plugin.showEntry(idsplit[(idsplit.length-1)]);
				});
			});
			
			if (s.centering){
				$entrieselement.find('ul').css('margin-left', Math.floor( (containerwidth - thiswidth) / 2) );
			}
		}
		
		plugin.replaceContent = function(newcontent){
			var s = plugin.settings;
			
			if (s.fadecontent){
				$contentelement.fadeTo( s.fadespeed, 0, function(){
					$(this).html(newcontent).fadeTo( s.fadespeed, 1.0 );
				});
			} else {
				$contentelement.html(newcontent);
			}
			lastactivity = (new Date).getTime();
		}
		
		plugin.showNext = function(){
			var s = plugin.settings;
			
			if (searchmode){
				
				var testyear = currentyear;
				var testentry = currententry;
				var entryfound = false;
				
				while(!entryfound){
					if (testentry < (s.data[testyear].length-1)){
						testentry++;
					} else {
						if (testyear < maxyear){
							testyear++;
						} else {
							testyear = minyear;
						}
						testentry = 0;
					}
					if ( s.data[testyear][testentry].searched == true ){
						entryfound = true;
					}
				}
				
				if (entryfound){
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).removeClass(s.activeclass);
					$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).removeClass(s.activeclass);
					if (currentyear != testyear){
						currentyear = testyear;
						currententry = testentry;
						plugin.createEntriesTimeline();
					} else {
						currentyear = testyear;
						currententry = testentry;
					}
					$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).addClass(s.activeclass);
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
					plugin.searchHighlight();
				}
				
			} else {
				
				if (currententry < (s.data[currentyear].length-1)){
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).removeClass(s.activeclass);
					currententry++;
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
				} else {
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).removeClass(s.activeclass);
					$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).removeClass(s.activeclass);
					if (currentyear < maxyear){
						currentyear++;
					} else {
						currentyear = minyear;
					}
					currententry = 0;
					plugin.createEntriesTimeline();
					$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).addClass(s.activeclass);
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
					plugin.searchHighlight();
				}
				
			}
			
			plugin.replaceContent(s.data[currentyear][currententry].content);
			
			s.onChange('next');
			
        }

		plugin.showPrev = function(){
			var s = plugin.settings;
			
			if (searchmode){
				
				var testyear = currentyear;
				var testentry = currententry;
				var entryfound = false;
				
				while(!entryfound){
					if (testentry > 0){
						testentry--;
					} else {
						if (testyear > minyear){
							testyear--;
						} else {
							testyear = maxyear;
						}
						testentry = s.data[testyear].length - 1;
					}
					if ( s.data[testyear][testentry].searched == true ){
						entryfound = true;
					}
				}
				
				if (entryfound){
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).removeClass(s.activeclass);
					$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).removeClass(s.activeclass);
					if (currentyear != testyear){
						currentyear = testyear;
						currententry = testentry;
						plugin.createEntriesTimeline();
					} else {
						currentyear = testyear;
						currententry = testentry;
					}
					$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).addClass(s.activeclass);
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
					plugin.searchHighlight();
				}
				
			} else {
				
				if (currententry > 0){
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).removeClass(s.activeclass);
					currententry--;
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
				} else {
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).removeClass(s.activeclass);
					$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).removeClass(s.activeclass);
					if (currentyear > minyear){
						currentyear--;
					} else {
						currentyear = maxyear;
					}
					currententry = s.data[currentyear].length - 1;
					plugin.createEntriesTimeline();
					$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).addClass(s.activeclass);
					$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
					plugin.searchHighlight();
				}
				
			}
				
			plugin.replaceContent(s.data[currentyear][currententry].content);
			
			s.onChange('prev');
        }
		
		plugin.showYear = function(year){
			var s = plugin.settings;
			
			$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).removeClass(s.activeclass);
			currentyear = year;
			plugin.createEntriesTimeline();
			$yearselement.find('#'+s.cssprefix+'_year_'+currentyear).addClass(s.activeclass);
			
			if (searchmode){
				
				var testentry = s.data[currentyear].length-1;
				var entryfound = false;
				
				while(!entryfound){
					if (testentry > 0){
						testentry--;
					} else {
						entryfound = true;
					}
					if ( s.data[currentyear][testentry].searched == true ){
						entryfound = true;
					}
				}
				
				currententry = testentry;
				
			} else {
				if (s.currententry == 'last'){
					currententry = s.data[currentyear].length - 1;
				} else {
					currententry = 0;
				}
			}
			
			$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
			
			plugin.replaceContent(s.data[currentyear][currententry].content);
			
			plugin.searchHighlight();
			s.onChange('year');
        }

		plugin.showEntry = function(nr){
			var s = plugin.settings;
			$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).removeClass(s.activeclass);
			currententry = nr;
			$entrieselement.find('#'+s.cssprefix+'_entry_'+currententry).addClass(s.activeclass);
			
			plugin.replaceContent(s.data[currentyear][currententry].content);
			
			s.onChange('entry');
        }

		plugin.init();

    }

    $.fn.timelineBrowser = function(options) {

        return this.each(function() {
            if (undefined == $(this).data('timelineBrowser')) {
                var plugin = new $.timelineBrowser(this, options);
                $(this).data('timelineBrowser', plugin);
            }
        });

    }

})(jQuery);

if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function(obj, start) {
	     for (var i = (start || 0), j = this.length; i < j; i++) {
	         if (this[i] === obj) { return i; }
	     }
	     return -1;
	}
}
