/**
 * sfCalendar
 *
 * @version: 1.5
 * @author SimpleFlame http://www.simpleflame.com/
 *
 * Required settings:
 *  display   - provide number of items displayed at once
 *
 * Other settings:
 *  label       - calendar heading 
 *  months      - labels for month names
 *  monthsShort - shortname labels for month names
 *  days        - labels for day names
 *  daysShort   - shortname labels for day names
 *  cityFilter  - should a dropdown with cities be visible
 */ 
(function($){

	var sfCalendar = function(el){
		this.$root = $(el);

		this.settings = {
			'label' : 'Events List',
			'months' : ['January','February','March','April','May','June','July','August','September','October','November','December'],
			'monthsShort' : ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
			'days' : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
			'daysShort' : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
			'defaultView' : 'today'
		};

		var options = arguments[1] || {};
		this.settings = $.extend(this.settings, options);

		this.items = this.parseData();

		this.structure();
		this.listing();
		this.calendar( );

		this.navigation();	

		if (this.settings.cityFilter === true) {
			this.cityFilter();
		}
		
		this.tagsList();
		
		this.init();
	};

	/*
	 * In order to compare dates we have to make sure that values match to to the millisecond,
	 * so every date has to be normalized.
	 * You can pass true as the second parameter to set to the end of the day
	 */
	sfCalendar.prototype.normalizeDate = function(date){
		if (!arguments[1]) {
			date.setHours(0);
			date.setMinutes(0);
			date.setSeconds(0);					
			date.setMilliseconds(0);		
		}
		else { //end of the day
			date.setHours(23);
			date.setMinutes(59);			
			date.setSeconds(59);			
			date.setMilliseconds(999);						
		}
		return date;
	};

	/*
	 * General structure of calendar listing
	 */
	sfCalendar.prototype.structure = function(){
		//custom main wrapper provided by user
		if (this.settings.mainWrapper) {
			this.$main = $(this.settings.mainWrapper);
		}
		else {
			this.$main = $('<div class="main"/>');	
			this.$root.append(this.$main);			
		}		

		this.$period = $('<h3 />');		
		this.$events = $('<div class="wrapper"/>');		
		if (this.settings.label) {
			this.$main.append('<h2>'+this.settings.label+'</h2>');
		}

		this.$main.append(this.$period, this.$events);
		
		//custom aside wrapper provided by user
		if (this.settings.asideWrapper) {
			this.$aside = $(this.settings.asideWrapper);
		}
		else {
			this.$aside = $('<div class="aside"/>');	
			this.$root.append(this.$aside);
		}
	};

	/*
	 * Explodes a comma separated string into an array of trimmed strings
	 */
	sfCalendar.prototype.parseTags = function(str){
		var tags = str.split(',');
		return $.map(tags,function(tag){
			tag = $.trim(tag); //removes whitespace
			return tag ? tag : null; //removes empty tags
		});
	};

	/*
	 * Reads events data from html
	 */
	sfCalendar.prototype.parseData = function(){
		var 
			items = [],
			self = this,
			tags = [],
			cities = [];

		var monthIndexes = {};	
		$.each(this.settings.monthsShort,function(index, item){
			monthIndexes[item] = index;
		});	

		this.$root.find('.data .item').each(function(eventIndex, item){


			var 
				location = $.trim($(this).find('.location').text()),
				itemTags = self.parseTags($(this).find('.tags').text()),
				description = $(this).find('.description').html(),
				time = $(this).find('.time').html(),
				title = $(this).find('.title').html(),
				thumb = $(this).find('.thumb').html(),
				city = $.trim($(this).find('.city').html()),
				locationDescription = $(this).find('.locationDescription').html(),
				regForm = $(this).find('.registration-form').html();

			//append item tags to global array
			$.each(itemTags, function(index, item){
				if ($.inArray(item, tags) === -1) {
					tags[tags.length] = item;					
				}
			});
			
			if (city && $.inArray(city, cities) === -1) {
				cities[cities.length] = city;
			}

			var startDateArr = $(this).find('.date .start').text().split('-');
			var startDate = new Date();			
			startDate.setFullYear(startDateArr[2], monthIndexes[startDateArr[1]], startDateArr[0]);
			startDate = self.normalizeDate(startDate);

			var eventDates = [startDate];

			var endDate = null;

			if ($(this).find('.date .end').length > 0 && $.trim($(this).find('.date .end').text()) !== '') {
				var endDateArr = $(this).find('.date .end').text().split('-');
				endDate = new Date();			
				endDate.setFullYear(endDateArr[2], monthIndexes[endDateArr[1]], endDateArr[0]);
				endDate = self.normalizeDate(endDate);				

				var startTime = startDate.getTime();
				var endTime = endDate.getTime();
				var oneDayMilliseconds = 60*60*24*1000;				
				var diffDays = (endTime - startTime)/oneDayMilliseconds;

				var tDate;

				for (var i = 1; i <= diffDays; i++){
					tDate = new Date();					
					tDate.setTime(startTime + i * oneDayMilliseconds);
					eventDates[eventDates.length] = tDate;
				}

			}

			$.each(eventDates,function(index, date){
				var event = {
					id : eventIndex, //unique id for add - simply index in the array of all events  
					description : description,
					location : location,
					time : time,
					tags : itemTags,
					date : date,
					startDate : startDate,
					endDate : endDate,
					title : title,
					thumb : thumb,
					city : city,
					locationDescription: locationDescription,
					regForm : regForm
				};			

				items[items.length] = event;				
			});

		});	

		this.tags = tags;
		this.activeTags = [];
		
		cities.sort();
		this.cities = cities;
		this.activeCity = null;

		//we no longer need data list
		this.$root.find('.data').remove();

		//sort items by date
		items.sort(function(a,b){
			if (a.date < b.date) {
				return -1;
			}
			if (a.date > b.date) {
				return 1;
			}
			return 0;
		});

		return items;
	};

	/* 
	 * Basically checks if any item tag is in the array of currently active tabs
	 */
	sfCalendar.prototype.isEventInActiveTags = function(item) {
		if (this.activeTags.length === 0) {
			return true;
		}

		var 
			self = this,
			flag = false;

		$.each(item.tags, function(index, tag){
			if ($.inArray(tag, self.activeTags) > -1) {
				flag = true;
				return false; //break out from the loop
			}
		});

		return flag;
	};
	
	/*
	 * Check if event is in active cities
	 */
	sfCalendar.prototype.isEventInActiveCity = function(item) {
		if (this.activeCity === null) {
			return true;
		}
		
		if (this.cities[this.activeCity] === item.city) {
			return true;
		}
		
		return false;
	};

	sfCalendar.prototype.checkFilters = function(item){
		if (this.isEventInActiveTags(item) === false) {
			return false;
		}		
		if (this.isEventInActiveCity(item) === false) {
			return false;
		}		
		
		return true;
	};
	
	/*
	 * Filters item set to return only these from a given month
	 */
	sfCalendar.prototype.fetchEventsForMonth = function(date){
		var 
			self = this,
			month = date.getMonth(),
			year = date.getFullYear();

		return $.grep(this.items, function(item){
			if (self.checkFilters(item) === false) {
				return false;
			}	
			return (item.date.getMonth() === month && item.date.getFullYear() === year);
		});
	};


	/* 
	 * Return events for a particular day
	 */	
	sfCalendar.prototype.fetchEventsForDay = function(date){
		var 
			self = this,
			month = date.getMonth(),
			year = date.getFullYear(),
			day = date.getDate();

		return $.grep(this.items, function(item){
			if (self.checkFilters(item) === false) {
				return false;
			}	
			return (item.date.getMonth() === month && item.date.getFullYear() === year && item.date.getDate() === day);
		});
	};

	/*
	 * Returns all events between a particular date
	 */
	sfCalendar.prototype.fetchEventsForPeriod = function(startDate, endDate){
		var 
			self = this;

		startDate = this.normalizeDate(startDate);
		endDate = this.normalizeDate(endDate, true); //second parameter this will set at the very last moment of the day		

		return $.grep(this.items, function(item){
			if (self.checkFilters(item) === false) {
				return false;
			}						
			return (item.date.valueOf() >= startDate.valueOf() && item.date.valueOf() <= endDate.valueOf());
		});
	};

	sfCalendar.prototype.fetchEventsFiltered = function(){
		var output = $.grep(this.items, $.proxy(function(item){
			return this.checkFilters(item);
		},this));
		
		return output.reverse();
	}
	/**
	 * Builds month navigation
	 */
	sfCalendar.prototype.navigation = function(){
		var 
			self = this,
			months = self.settings.months,
			startDate = arguments[0] || new Date();			

		//tabs
		this.$navigation = $('<p class="nav"/>').click(function(e){
			if (e.target.nodeName.toLowerCase() !== 'a') {
				return true;
			}

			e.preventDefault();
			var date = $(e.target).data('date');

			//rebuild tabs with new Date as a starter						
			self.navigation(date);
			self.rebuildCalendar(date);
			self.repopulateCalendar(date);			

			//reactive current selection
			var event = self.$calendar.data('selection');			
			$(document).trigger(event.type, event.data);
		});

		//builds previous and next links 
		var createLink = function(offset, className){
			var
				newDate = new Date(),
				newMonth = startDate.getMonth() + offset,
				newYear = startDate.getFullYear();

			if (newMonth < 0) {
				newMonth = newMonth + 12;
				newYear = newYear - 1;
			}
			//next year
			else if (newMonth > 11){
				newMonth = newMonth - 12;
				newYear = newYear + 1;
			}				

			newDate.setFullYear(newYear,newMonth,1);
			return $('<a href="#" class="' + className + '">' + months[newMonth] + '</a>').data('date',newDate);
		};

		var 
			$prev = createLink(-1, 'prev'),
			$next = createLink(1, 'next');

		this.$navigation.append($prev, document.createTextNode(' '+months[startDate.getMonth()]+' '+startDate.getFullYear()), $next);			

		//cleanup from previous navigation
		this.$aside.find('.nav').unbind('click').remove();

		//readd tabs
		this.$aside.prepend(this.$navigation);	
	};

	/* 
	 * Initializes listing 
	 */
	sfCalendar.prototype.listing = function(){
		var self = this;

		var updateListing = function(dataItems) {
			var 
				days = self.settings.days,
				months = self.settings.monthsShort;

			self.$events.empty(); //remove previous items

			//no results for given month
			if (dataItems.length === 0) {
				self.$events.append('<p class="empty">No events to show</p>');
				return;
			}

			var previousDate = null;

			$.each(dataItems, function(index, item){

				var isNewDate = false;

				//create a new date wrapper
				if (previousDate === null || previousDate.toString() !== item.date.toString()) {
					isNewDate = true;

					var 
						$wrapper = $('<div class="day"/>'),
						day = item.date.getDate();

					if (day < 10) {
						day = '0'+day;
					}
					$wrapper.append('<h4>'+months[item.date.getMonth()]+' <span>'+day+'</span></h4>');
					$wrapper.append('<p class="weekday">'+days[item.date.getDay()]+'</p>');

					self.$events.append($wrapper);
					previousDate = item.date;
				}

				var el = $('<div class="event"/>');

				//check if first item
				if (isNewDate === true) {
					el.addClass('event-first');
				}
				//title
				if (item.title) {
					el.append('<h5>'+ item.title + '</h5>');
				}

				if (item.city) {
					el.append('<p class="meta"><span>City:</span> ' + item.city);
				}
				
				if (item.endDate === null){
					el.append('<p class="meta"><span>Date:</span> ' + self.settings.months[item.startDate.getMonth()] + ' ' + item.startDate.getDate() + ', ' + item.startDate.getFullYear() + '</p>');
				}				
				else {
					el.append('<p class="meta"><span>Date:</span> ' + self.settings.months[item.startDate.getMonth()] + ' ' + item.startDate.getDate() + ', ' + item.startDate.getFullYear() + ' to ' + self.settings.months[item.endDate.getMonth()] + ' ' + item.endDate.getDate() + ', ' + item.endDate.getFullYear() + '</p>');
				}
				
				el.append('<p class="meta">' + item.time + '</p>');

				if (item.locationDescription) {
					el.append('<div class="location-description"><p class="meta"><span>Locations:</span></p>' + item.locationDescription + '</p></div>');
				}
				
				if (item.description) {
					el.append('<div class="event-desc"><p class="meta"><span>Event description</span></p>' + item.description + '</div>');
				}
				
				if (item.thumb) {
					el.append('<p class="thumb">'+ item.thumb + '</p>');
				}
				
				if (item.regForm && $.inArray('private', item.tags) === -1 && $.inArray('Private', item.tags) === -1){
					el.append(item.regForm);
					el.addClass('has-registration-form')
				}

				self.$events.find('.day:last').append(el);

				if (item.location && google.maps) {			

					var id = 'event-map-'+item.id;

					var geocoder = new google.maps.Geocoder();

					var showMap = function(){
						var location = $(arguments[0][0]).data('location');
						var container = $($('#'+id)).get(0);

						var map = new google.maps.Map(container, {
					    zoom: 14,
					    mapTypeId: google.maps.MapTypeId.ROADMAP			
						});

						geocoder.geocode( { 'address' : location }, function(results, status){

			        if (status == google.maps.GeocoderStatus.OK) {
			          map.setCenter(results[0].geometry.location);
			          var marker = new google.maps.Marker({
			              map: map, 
			              position: results[0].geometry.location
			          });
			        } else {
			          alert("Geocode was not successful for the following reason: " + status);
			        }									
						});						
					};
				
					var $mapTrigger = $('<a/>', { 
						href: '#'+id, 
						text : 'Map it!',
						data : {
							location : item.location
						}
					}).fancybox({
						frameWidth : 640,
						frameHeight : 450,
						onComplete : showMap,
						autoscale: false,
						content: $('<div />',{
							id: id,
							"class" : "gmap-container",
							css : {
								width: 640,
								height: 450
							}
						})
					});

					var $mapWrapper = $('<p class="map"/>').append($mapTrigger);
					el.append($mapWrapper);
					el.addClass('has-map')
				}
			});			
		};

		//update listing when date is change in the calendar
		$(document).bind('eventbox.setDay', function(event,date){
			self.$period.html('<span>Day:</span> ' + self.settings.months[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear());
			updateListing(self.fetchEventsForDay(date));
		});

		$(document).bind('eventbox.setMonth', function(event,date){
			self.$period.html('<span>Month:</span> ' + self.settings.months[date.getMonth()] + ' ' + date.getFullYear());			
			updateListing(self.fetchEventsForMonth(date));
		});

		$(document).bind('eventbox.setWeek', function(event,startDate,endDate){
			self.$period.html('<span>Week:</span> ' + self.settings.months[startDate.getMonth()] + ' ' + startDate.getDate() + ' - '+ self.settings.months[endDate.getMonth()] + ' ' + endDate.getDate() + ', ' + startDate.getFullYear());						
			updateListing(self.fetchEventsForPeriod(startDate,endDate));
		});						
		
		$(document).bind('eventbox.allEvents',function(event){
			self.$period.html('<span>Events</span>');
			updateListing(self.fetchEventsFiltered());
		});
	};

	sfCalendar.prototype.cityFilter = function(){
		var
			self = this,
			$cityFilter = $('<select class="city-filter"/>');
			
		$cityFilter.append('<option value="-1"></option>');
		
		$.each(this.cities, function(index){
			var option = $('<option value="'+ index + '">' + this + '</option>');
			$cityFilter.append(option);
		});
		
		$cityFilter.change(function(){
			
			self.activeCity = parseInt($(this).val(), 10) === -1 ? null : parseInt($(this).val(),10);
			
			//update calendar widget
			self.repopulateCalendar(self.$calendar.data('date'));

			//refresh current selection
			
			if (self.activeCity === null) {
				var event = self.$calendar.data('selection');			
				$(document).trigger(event.type, event.data);			
			}
			else {			
				$(document).trigger('eventbox.allEvents');							
			}
		});
		
		this.$aside.append($cityFilter);
	};
		
	/*
	 * Tags filter list
	 */
	sfCalendar.prototype.tagsList = function(){
		var 
			self = this,
			$tagsList = $('<ul class="filter" />');		

		//function launched on checkbox click
		var triggerClick = function(e){
			var data = [];

			$tagsList.find('input:checked').each(function(){
				data[data.length] = $(this).data('tag');
			});

			self.activeTags = data;

			//update calendar widget
			self.repopulateCalendar(self.$calendar.data('date'));

			//refresh current selection
			if (self.activeTags.length === 0) {
				var event = self.$calendar.data('selection');			
				$(document).trigger(event.type, event.data);							
			}
			else {
				$(document).trigger('eventbox.allEvents');				
			}
		};

		$.each(this.tags, function(index, item){
			var
				$li = $('<li><label for="event-filter-'+index+'"> '+item+'</label></li>'),
				$checkbox = $('<input type="checkbox" id="event-filter-'+index+'" />').data('tag',item);

			$checkbox.click(triggerClick);

			$li.find('label').prepend($checkbox);
			$tagsList.append($li);
		});

		this.$aside.append($tagsList);			
	};

	/*
	 * Builds calendar widget
	 */
	sfCalendar.prototype.calendar = function(){
		var self = this;
		this.$calendar = $('<div class="calendar"/>');

		//catches clicks on the whole calendar widget
		this.$calendar.click(function(e){
			if (e.target.nodeName.toLowerCase() !== 'a') {
				return;
			}
			e.preventDefault();

			var $target = $(e.target);

			//month cell click
			if ($target.hasClass('month')) {
				$(document).trigger('eventbox.setMonth',[$target.data('date')]);
			}
			//week cell click
			else if ($target.hasClass('week')) {
				$(document).trigger('eventbox.setWeek',[$target.data('date.start'), $target.data('date.end')]);
			}
			//day cell click
			else {
				$(document).trigger('eventbox.setDay',[$target.data('date')]);
			}
		});

		//selecting whole month
		$(document).bind('eventbox.setMonth',function(event, date){	
			date = self.normalizeDate(date);

			self.$calendar.data('selection',{
				'type' : 'eventbox.setMonth',
				'data' : [date]
			});						

			if (date.valueOf() === self.$calendar.data('date').valueOf()) {
				self.$calendar.find('td a').addClass('selected');
			}
		});

		//selecting only one week
		$(document).bind('eventbox.setWeek',function(event, startDate, finishDate){
			self.$calendar.data('selection',{
				'type' : 'eventbox.setWeek',
				'data' : [startDate, finishDate]
			});			

			self.$calendar.find('td a').removeClass('selected');

			self.$calendar.find('tbody th a').each(function(){
				if ($(this).data('date.start').valueOf() === startDate.valueOf()) {
					$(this).parents('tr').find('td a').addClass('selected');
				}
			});
		});		

		//selecting a particular day
		$(document).bind('eventbox.setDay', function(event, date){

			self.$calendar.data('selection',{
				'type' : 'eventbox.setDay',
				'data' : [date]
			});

			self.$calendar.find('td a').removeClass('selected');

			self.$calendar.find('tbody td a').each(function(){
				if ($(this).data('date').valueOf() === date.valueOf()) {
					$(this).addClass('selected');
				}
			});
		});

		var now = new Date();

		this.rebuildCalendar(now);
		this.repopulateCalendar(now);
		this.$aside.append(this.$calendar);		
	};

	/*
	 * Fetches events for current month and marks them in the calendar
	 */
	sfCalendar.prototype.repopulateCalendar = function(date){
		var 
			tdate, weekday,
			self = this,
			dataItems = self.fetchEventsForMonth(date);

		tdate = date;
		tdate.setDate(1);
		weekday = tdate.getDay();

		this.$calendar.find('a.event').removeClass('event');

		$.each(dataItems, function(){
			var day = this.date.getDate() + weekday - 1; //we add weekday as it's the offset at the beginning of the calendar
			self.$calendar.find('td').eq(day).find('a').addClass('event');
		});				
	};

	/*
	 * Creates HTML for calendar widget
	 */ 
	sfCalendar.prototype.rebuildCalendar = function(date){

		date.setDate(1); //reset to the first day of passed month
		date = this.normalizeDate(date);

		var 
			weekday, rows, $row, $cell, $trigger, daysLimit, dayDate,
			counter = 0,
			displayedDay = 1,
			daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31],

			$table = $('<table summary="Calendar for ' + parseInt(date.getMonth() + 1, 10) + '.'+ date.getFullYear() +'"><thead/><tbody/></table>'),
			selectWeekStartDate, selectWeekEndDate;

		//cleanup
		this.$calendar.empty(); //remove previous items
		this.$calendar.data('date',date);

		if (date.getFullYear() % 4 === 0) {
			daysInMonth[1] = 29;
		}

		//weekday of the first day of current month
		weekday = date.getDay();
		daysLimit = daysInMonth[date.getMonth()] + weekday;
		rows = Math.ceil(daysLimit / 7);

		//header row
		$row = $('<tr />');
		$trigger = $('<a href="#" class="month">M</a>').data('date',date); //month changing trigger
		$cell = $('<th scope="col"/>');
		$row.append($cell.append($trigger));

		//day names
		$.each(this.settings.daysShort, function(){
			$row.append('<th scope="col">'+this+'</th>');
		});

		$table.find('thead').append($row);

		var firstDayOfMonth = false;

		for (var i = 0; i < rows; i++) {
			//week selecting row
			$row = $('<tr />');

			//cells
			for (var j = 0; j < 7; j++) {
				$cell = $('<td class="col' + parseInt(j+1,10) + '"/>');

				//existing day in month
				if (counter >= weekday && counter < daysLimit) {

					dayDate = new Date(date.getFullYear(),date.getMonth(),displayedDay,0,0,0);

					//look for the first day in month/week
					if (firstDayOfMonth === false || j === 0) {
						selectWeekStartDate = dayDate;
					}
					firstDayOfMonth = true;

					//look for the last day of the week
					if (j === 6 || counter + 1 === daysLimit) { 
						selectWeekEndDate = dayDate;
					}

					$trigger = $('<a href="#">'+ displayedDay +'</a>').data('date', dayDate);
					$cell.append($trigger);
					displayedDay++;
				}
				else {
					$cell.html('&nbsp;');
				}

				counter++;
				$row.append($cell);
			}

			//week selection trigger			
			$cell = $('<th scope="row"/>');
			$trigger = $('<a href="#" class="week">W</a>').data('date.start',selectWeekStartDate).data('date.end',selectWeekEndDate);			
			$row.prepend($cell.append($trigger));

			$table.find('tbody').append($row);
		}

		this.$calendar.append($table);
	};

	sfCalendar.prototype.init = function(){
		
		var now = this.normalizeDate(new Date());					
		
		//active today's date
		switch (this.settings.defaultView) {
			case 'month':
				now.setDate(1);
				$(document).trigger('eventbox.setMonth',[ now ]);
			break;
			default:
				$(document).trigger('eventbox.setDay',[ now ]);				
			break;				
		}
		
	};
	
	$.fn.sfCalendar = function(options){
		return $(this).each(function(){
			return new sfCalendar(this,options);
		});
	};

})(jQuery);

/**
 * Twit
 *  jQuery Plugin to Display Twitter Tweets on a Blog.
 *  http://code.google.com/p/jquery-twit/
 *
 * Copyright (c) 2009 Yusuke Horie
 *
 * Released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Since  : 0.1.0 - 08/26/2009
 * Version: 0.1.0 - 08/26/2009
 */
(function(jQuery){var _i=0;jQuery.fn.twit=function(user,options){if(typeof user!='string')return this;var opts=jQuery.extend({},jQuery.fn.twit.defaults,options),c=jQuery.isFunction(opts.callback)?opts.callback:_callback,url='',params={};opts.user=user;url='http://twitter.com/statuses/user_timeline/'+opts.user+'.json';params.count=opts.count;return this.each(function(i,e){var $e=$(e);if(!$e.hasClass('twit'))$e.addClass('twit');jQuery.ajax({url:url,data:params,dataType:'jsonp',success:function(o){c.apply(this,[(o.results)?o.results:o,e,opts])}})})};jQuery.fn.twit.defaults={user:null,callback:null,icon:true,username:true,text:true,count:200,limit:7,label:'Twitter',title:''};var _callback=function(o,e,opts){var $this=$(e);if(!o||o.length==0||$this.length==0)return false;$this.data('_inc',1);_i++;var username=o[0].user.screen_name,icon=o[0].user.profile_image_url;var h='<div class="twitHeader">'+' <span class="twitLabel">'+opts.label+'</span>&nbsp;&nbsp;'+' <span class="twitTitle">'+opts.title+'</span>'+'</div>';if(opts.icon||opts.username){h+='<div class="twitUser">';if(opts.icon)h+=' <a href="http://twitter.com/'+username+'/">'+'  <img src="'+icon+'" alt="'+username+'" title="'+username+'" style="vertical-align:middle;" />'+' </a>&nbsp;&nbsp;';if(opts.username)h+='<a href="http://twitter.com/'+username+'/">'+username+'</a>';h+='</div>'}h+='<ul class="twitBody" id="twitList'+_i+'">'+_build(o,$this,opts)+'</ul>';$this.html(h);$('#twitList'+_i+' a.twitEntryShow').live('click.twitEntryShow'+_i,function(event){event.preventDefault();var $t=$(this);$t.parent().fadeOut(400,function(){var i=$this.data('_inc');i++;$this.data('_inc',i);if($t.hasClass('twitEntryAll')){$t.die('click.twitEntryShow'+_i);var start=(i*opts.limit)-opts.limit;$(this).after(_build(o,$this,opts,start,o.length)).remove()}else{$(this).after(_build(o,$this,opts)).remove()}})})};var _build=function(o,$t,opts,s,e){var h='',inc=$t.data('_inc'),start=s||(inc*opts.limit)-opts.limit,end=e||((o.length>start+opts.limit)?start+opts.limit:o.length);for(var i=start;i<end;i++){var t=o[i],username=t.user.screen_name,icon=t.user.profile_image_url;h+='<li class="twitEntry">';if(opts.text){var text=t.text.replace(/(https?:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)/,function(u){var shortUrl=(u.length>30)?u.substr(0,30)+'...':u;return'<a href="'+u+'">'+shortUrl+'</a>'}).replace(/@([a-zA-Z_]+)/g,'@<a href="http://twitter.com/$1">$1</a>').replace(/(?:^|\s)#([^\s\.\+:!]+)/g,function(a,u){return' <a href="http://twitter.com/search?q='+encodeURIComponent(u)+'">#'+u+'</a>'});h+=' <span>'+text+'</span>'}h+='</li>'}if(o.length>end){h+='<li class="twitNavi">'+'<a href="#" class="twitEntryShow">more</a> &nbsp;/&nbsp;';if(o.length>opts.limit)h+='<a href="#" class="twitEntryShow twitEntryAll">all</a>';h+='</li>'}return h}})(jQuery);


/*!
 * CSS Browser Selector v0.4.0 (Nov 02, 2010)
 * http://rafael.adm.br/css_browser_selector
 */
function css_browser_selector(u){var ua=u.toLowerCase(),is=function(t){return ua.indexOf(t)>-1},g='gecko',w='webkit',s='safari',o='opera',m='mobile',h=document.documentElement,b=[(!(/opera|webtv/i.test(ua))&&/msie\s(\d)/.test(ua))?('ie ie'+RegExp.$1):is('firefox/2')?g+' ff2':is('firefox/3.5')?g+' ff3 ff3_5':is('firefox/3.6')?g+' ff3 ff3_6':is('firefox/3')?g+' ff3':is('gecko/')?g:is('opera')?o+(/version\/(\d+)/.test(ua)?' '+o+RegExp.$1:(/opera(\s|\/)(\d+)/.test(ua)?' '+o+RegExp.$2:'')):is('konqueror')?'konqueror':is('blackberry')?m+' blackberry':is('android')?m+' android':is('chrome')?w+' chrome':is('iron')?w+' iron':is('applewebkit/')?w+' '+s+(/version\/(\d+)/.test(ua)?' '+s+RegExp.$1:''):is('mozilla/')?g:'',is('j2me')?m+' j2me':is('iphone')?m+' iphone':is('ipod')?m+' ipod':is('ipad')?m+' ipad':is('mac')?'mac':is('darwin')?'mac':is('webtv')?'webtv':is('win')?'win'+(is('windows nt 6.0')?' vista':''):is('freebsd')?'freebsd':(is('x11')||is('linux'))?'linux':'','js']; c = b.join(' '); h.className += ' '+c; return c;}; css_browser_selector(navigator.userAgent);

/*!
 * (v) Compact labels plugin (v20110124)
 * Takes one option: labelOpacity [default: true] set to false to disable label opacity change on empty input focus
 */
(function($){$.fn.compactize=function(options){var defaults={labelOpacity:true};options=$.extend(defaults,options);return this.each(function(){var label=$(this),input=$('#'+label.attr('for'));input.focus(function(){if(options.labelOpacity){if(input.val()===''){label.css('opacity','0.5');}}else{label.hide();}});input.keydown(function(){label.hide();});input.blur(function(){if(input.val()===''){label.show();if(options.labelOpacity){label.css('opacity',1);}}});window.setTimeout(function(){if(input.val()!==''){label.hide();}},50);});};})(jQuery);

/*!
 * (v) hrefID jQuery extention
 * returns a valid #hash string from link href attribute in Internet Explorer
 */
(function($){$.fn.extend({hrefId:function(){return $(this).attr('href').substr($(this).attr('href').indexOf('#'));}});})(jQuery);

/*!
 * Scripts
 *
 */
jQuery(function($) {
 
	var Engine = {
		utils : {
			links : function(){
				$('a[rel*="external"]').click(function(e){
					e.preventDefault();
					window.open($(this).attr('href'));
				});
			},
			mails : function(){
				$('a[href^="mailto:"]').each(function(){
					var mail = $(this).attr('href').replace('mailto:','');
					var replaced = mail.replace('/at/','@');
					$(this).attr('href','mailto:'+replaced);
					if($(this).text() === mail) {
						$(this).text(replaced);
					}
				});
			}
		},
		forms : {
			labels : function() {
				$('#search-form label').compactize();
				$('.form-b label').compactize();
			}
		},
		ui : {
			rotator : function() {
				var 
				options = arguments[0] || {},
				defaults = {
					interval : 5000,
					autorotate : true
				};

				options = $.extend(defaults,options);

				$('.showcase-a').each(function(e){
					var 
				 	triggers = $(this).find('.controls a'),
					tabs = $(this).find('div.tab'),
					current = 0,
					interval;

					tabs.hide().eq(0).show();

					triggers.each(function(index, item){
						$(this).data('index',index);
					});

					var moveTo = function(pos) {
						current = pos;
						tabs.hide().eq(pos).fadeIn();
						triggers.removeClass('active').eq(pos).addClass('active');
					};

					triggers.click(function(e){
						e.preventDefault();
						moveTo($(this).data('index'));
					});

					//only if autorotate option is on
					if (options.autorotate) {
						interval = window.setInterval(function(){
							//loop back to the first tab
							var pos = current + 1;

							if (pos >= tabs.length) {
								pos = 0;
							}
							moveTo(pos);
						}, options.interval);

						//clear autorotation when you hover over the rotator
						$(this).mouseenter(function(){
							window.clearInterval(interval);
						});
					}
					
					if(jQuery(".controls li a.active").length < 1){
						jQuery(".controls li:first a").addClass("active");
					}
					
				});
			}
		},
		fixes : {
			enhancements : function() {
				if($.browser.msie && parseInt($.browser.version,10) < 9){
					$(':last-child:not(cufon)').addClass('last-child');
					$('#nav > div > ul > li').prepend('<span class="before">|</span>');
					$('#nav > div > ul > li.selected > a').prepend('<strong class="border">|</strong>');
					$('#footer ul li').prepend('<span class="before">|</span>');
				}
			}
		},
		
		tweaks : {
			
			activeNav : function(){
				// adds selected state to blog drill down main nav item.
				if(jQuery("body.blog").length > 0){
					jQuery("li#main-nav-blog").addClass("selected");
				}	
			},
			
			latestTweets : function(){
                         if(location.href.indexOf("worldsecuresystems") != -1){
                              jQuery("div.tweetsContainer, a.addthis_button_tweet").remove();
                         }else{
                              // if we are not secure then run tweets
                              if ($('#tweets').size() === 0) { return;}
                   
                                   $('#tweets').twit('MindlogikLtd', {
                                     limit: 8,
                                     icon: false
                                   });    
                         }
                    },
					
					
					faqSlide : function(){
					// contols faq section / behavior
					if(jQuery("ul.questions li a").size === 0){	return;	}
					
					   jQuery("ul.questions li a").each(function(){
							 jQuery(this).click(function(){
							 
								 jQuery(this).parent().find("div.faqAnswer").slideToggle();
								 jQuery(this).toggleClass("faqBold");
									 return false;
					 
							 });
							 
							 jQuery("div.faqAnswer a").click(function(){
									window.location = jQuery(this).attr("href");
								}); 
							 
							 
					   });   
					}, // faqSlide
					
					
				calendar : function(){
					$('#events-a').sfCalendar({
						
						defaultView : 'month',
						asideWrapper : '#events-aside'
					});
				}, // calendar
				
				fancyGallery : function(){
                        
                        
                         if(jQuery("td.photogalleryItem").length > 0){
                   
                              jQuery("td.photogalleryItem").each(function(){
                                   if(jQuery(this).find("a").length > 0 )     {                                        var link = jQuery(this).find("a").attr("href");
                                        var img = jQuery(this).find("img").attr("src");
                                        jQuery(this).html("<a href='"+link+"' class='fancyBox' rel='Gallery'><img src='"+img+"'></a>");
                                   }
                                  
                              });
                          }
                        
						if(jQuery("a.fancyBox").length > 0){
						
                         jQuery("a.fancyBox").fancybox({
								'transitionIn'	: 'elastic',
								'transitionOut'	: 'elastic'
							});
						}
                        
                    } // fancyGallery


			
		}// tweaks
	};

	Engine.utils.links();
	Engine.utils.mails();
	Engine.forms.labels();
	Engine.ui.rotator();
	Engine.fixes.enhancements();
	
	Engine.tweaks.activeNav();
	Engine.tweaks.latestTweets();
	Engine.tweaks.faqSlide();
	Engine.tweaks.calendar();
	Engine.tweaks.fancyGallery();
	
});
