/* jQuery ConferenceTracks plugin: displays conference tracks in calendar style. */

/*
TODO: highlight only attending events, make star work
*/

(function($) {

$.fn.conferencetracks = function(options){
	var defaults = {
		json_url: null,
		json_string: null,
		border_width: 1,	// width of the border of a talk
		unit_height: 1		// pixels per minute
	};
	var opts = $.extend(defaults, options);
	var json;
	var __this = this;
	
	if (opts.json_string) {
		ct_init(opts.json_string, __this, opts);
	} else if (opts.json_url) {
		$.getJSON(opts.json_url, function(data){
			ct_init(data, __this, opts);
		});
	} else {
		alert('No JSON string or URL.');
		return false;
	}
};

var talks_start_end_times = [];
var server_time, time_difference;

function ct_init(json, __this, opts) {
	if (!json || json.length == 0) {
		alert('Empty JSON object.');
		return false;
	}
	
	var server_time = new Date();
	server_time.setISO8601(json.current_time.time);
	var local_time = new Date();
	time_difference = server_time.getTime() - local_time.getTime();

	__this.each(function(index){
		var this_id = __this.attr('id');
		var this_width = $(this).innerWidth();
		var times_width = 60;
		$(this).html('<div class="controls" id="'+this_id+'_controls"></div>').addClass('ct_wrap');
		var controls = $(this).find('div.controls');
		var pretty_date = {};
		
		var html = '';
		
		for (var i in json.days) {
			var day = json.days[i].day;
			
			var starttime = new Date();
			starttime.setISO8601(day.start_time);
			pretty_date[day.date] = ct_weekday(starttime.getDay())+', '+ct_month(starttime.getMonth())+' '+starttime.getDate();
			var endtime = new Date();
			endtime.setISO8601(day.end_time);
			
			var hours = Math.ceil(endtime.getHours() - starttime.getHours()) + 1;
			
			var tracks_with_talks = [];
			for (var j in day.tracks) {
				var track = day.tracks[j].track;
				if (track.talks.length > 0) {
					tracks_with_talks.push(track);
				}
			}
			
			if (tracks_with_talks.length > 0) {
				var track_width = Math.floor(this_width / tracks_with_talks.length) - times_width;
				html += '<div class="ct_day"><h2>'+pretty_date[day.date]+'</h2>';
				html += '<ul class="times">';
				for (i = 0; i < (hours + 1); i++) {
					html += '<li style="height: '+Math.ceil((60 * opts.unit_height) - 1)+'px">'+ct_hour(starttime.getHours() + i)+':00</li>';
				}
				html += '</ul>';
				html += '<ul class="ct_tracks" style="height: '+Math.ceil((hours + 1) * 60 * opts.unit_height)+'px">';
				for (var j in tracks_with_talks) {
					var track = tracks_with_talks[j];
					html += '<li class="ct_track" style="width: '+track_width+'px"><h3>'+track.title+'</h3><ul class="ct_talks">';
					
					for (var k in track.talks) {
						var talk = track.talks[k].talk;
						var talk_starttime = new Date();
						talk_starttime.setISO8601(talk.start_time);
						var day_start = new Date();
						day_start.setTime(talk_starttime.valueOf());
						day_start.setHours(starttime.getHours());
						day_start.setMinutes(0);
						day_start.setSeconds(0);
						var talk_offset = talk_starttime.getTime() - day_start.getTime();
						var end_time = new Date();
						end_time.setTime(talk_starttime.getTime() + (talk.duration * 60000));
						talks_start_end_times.push({'id': talk.id, 'start_time': talk.start_time, 'end_time': end_time});
						html += '<li class="ct_talk" id="'+this_id+'_'+talk.id+'" style="height: '+Math.ceil((talk.duration * opts.unit_height) - (opts.border_width * 2))+'px; top: '+(Math.ceil((talk_offset / 60000) * opts.unit_height))+'px; width: '+(track_width - 3 - opts.border_width)+'px">';
						html += '<h4><a href="'+talk.url+'">'+talk.title+'</a></h4>';
						html += '<p>';
						if (talk.speaker) {
							html += 'by <strong>'+talk.speaker.registration.full_name+'</strong><br />';
						}
						html += 'location: <strong>'+talk.location+'</strong><br />start: <strong>'+ct_pad(talk_starttime.getHours())+':'+ct_pad(talk_starttime.getMinutes())+'</strong><br />duration: <strong>'+talk.duration+' min.</strong>';
						if (talk.description) {
							html += '<br /><br />'+talk.description;
						}
						html += '</p>';
//							html += '<a class="star'+(talk.registration_talk ? ' starred' : '')+'" href="#" onlick="return false">'+(talk.registration_talk ? 'I will attend this (click to change)' : 'I won\'t attend this (click to change)')+'</a>';
						html +='</li>';
					}
					
					html += '</ul></li>';
				}
				html += '</ul></div>';
			}
		}
		
		$(this).append(html);
		
		// mouseovers
		var talks = $(this).find('li.ct_talk');
		talks.hover(
			function(){
				$(this).addClass('hover').css({'height': 'auto', 'min-height': $(this).css('height')});
			},
			function(){
				$(this).removeClass('hover').css({'height': $(this).css('min-height'), 'min-height': '0'});
			}
		);
		
		ct_highlight_current(__this);
		setInterval(function(){ct_highlight_current(__this)}, 120000);
	});
}

function ct_highlight_current(__this) {
	var this_id = __this.attr('id');
	var zone_time = ct_get_server_time();
	$.each(talks_start_end_times, function(k, v){
		var start_time = new Date();
		start_time.setISO8601(v.start_time);
		var end_time = new Date();
		end_time.setISO8601(v.end_time);
		var talk = $('#'+this_id+'_'+v.id);
		if (start_time <= zone_time && end_time > zone_time) {
			talk.addClass('current');
		} else {
			talk.removeClass('current');
		}
	});
}

function ct_get_server_time() {
	var date = new Date();
	date.setTime(date.getTime() + time_difference);
	
	return date;
}

function ct_hour(hour) {
	return (hour > 23) ? (hour - 24) : hour;
}

function ct_weekday(i) {
	switch (i) {
		case 0:
			return 'Sunday';
		case 1:
			return 'Monday';
		case 2:
			return 'Tuesday';
		case 3:
			return 'Wednesday';
		case 4:
			return 'Thursday';
		case 5:
			return 'Friday';
		case 6:
			return 'Saturday';
	}
}

function ct_month(i) {
	switch (i) {
		case 0:
			return 'January';
		case 1:
			return 'February';
		case 2:
			return 'March';
		case 3:
			return 'April';
		case 4:
			return 'May';
		case 5:
			return 'June';
		case 6:
			return 'July';
		case 7:
			return 'August';
		case 8:
			return 'September';
		case 9:
			return 'October';
		case 10:
			return 'November';
		case 11:
			return 'December';
	}
}

function ct_pad(i) {
	return (i < 10) ? '0'+i : i;
}

})(jQuery);

Date.prototype.setISO8601 = function(dString){
	if (dString == null) {
		return null;
	}
	var regexp = /(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)(:)?(\d\d)(\.\d+)?(Z|([+-])(\d\d)(:)?(\d\d))/;
	if (dString.toString().match(new RegExp(regexp))) {
		var d = dString.match(new RegExp(regexp));
		var offset = 0;

		this.setUTCDate(1);
		this.setUTCFullYear(parseInt(d[1],10));
		this.setUTCMonth(parseInt(d[3],10) - 1);
		this.setUTCDate(parseInt(d[5],10));
		this.setUTCHours(parseInt(d[7],10));
		this.setUTCMinutes(parseInt(d[9],10));
		this.setUTCSeconds(parseInt(d[11],10));
		if (d[12])
		this.setUTCMilliseconds(parseFloat(d[12]) * 1000);
		else
		this.setUTCMilliseconds(0);
		if (d[13] != 'Z') {
			offset = (d[15] * 60) + parseInt(d[17],10);
			offset *= ((d[14] == '-') ? -1 : 1);
			this.setTime(this.getTime() - offset * 60 * 1000);
		}
	}
	else {
		this.setTime(Date.parse(dString));
	}
	return this;
};