// FIXME? this file is kind of getting out of hand, it might be nice to split this up a bit

// create a skiclubz namespace for application-specific global data
if(!$.skiclubz) $.skiclubz = {};
jQuery.extend($.skiclubz, {
	overlays: {},
	videos: {}, // currently used to help with the "both" buttons for splitscreen
	eventToCopy: {}, // event attributes that will be saved when the user clicks "copy"
	copiedEvent: {}, // TODO? could get fancy and use localstorage for this (would need a fallback for IE7)
	baseUrl: '', // this is set in the main layout.  can remain blank as long as the application runs on the root of a domain or subdomain.
	user: {}, // this is set in the main layout.  holds information about the currently logged-in user (right now only contains id)
	notificationsShown: 0, // is set below to the number of notifications shown on the page onload
	
	// global functions:
	initializeTabs: function() { $('ul.tabs').show().tabs('#panes > .in', {tabs: 'a:not(.not-a-tab)'}); }, // making this globally accessible allows re-rendering tabs after ajax, etc
	loadAssignableAthletesOnChange: function() { if(console) console.err('Not initialized yet!'); }, // see below for what this is set to and why it is necessary (FIXME: try to make it not necessary!)
	flash: function(message, type) {
		if(typeof(message) == 'object') { // allow passing an object for ease of use (of the form {'success':'message'})
			$.each(['success', 'notice', 'error'], function(n, type) {
				$.skiclubz.flash(message[type], type);
			});
		} else if(typeof(message) == 'string') {
			type = type || 'notice';
			var flash = $('<div class="section">' + message + '</div>').addClass(type).hide();
			$('#flashes').append(flash.fadeIn());
		}
	},
	replaceFlash: function(message, type) { // this flash will replace any existing flash messages
		$('#flashes').empty();
		$.skiclubz.flash(message, type);
	},
	imageCache: [],
	preloadImage: function(src) {
		$.skiclubz.imageCache.push($('<img>').attr('src', src));
	},
	preloadImages: function(srcs) {
		jQuery.each(srcs, function(index, src) {
			$.skiclubz.preloadImage(src);
		});
	},
	initGroupTreeSelect: function() { if(console) console.log('Did you forget to include groupTreeSelect.js?'); }, // this shouldn't get called unless groupTreeSelect.js is included, but just in case
	/**
	 * Utility method to strip non-numeric characters from a string (useful for getting a primary
	 * key from an element's id, for example).
	 */
	stripNonNumeric: function(str) {
		return str.replace(/[^0-9]/g, '');
	},
	/**
	 * Scroll to the top of the passed id if the window is currently scrolled more than 50 pixels 
	 * below that point.
	 * NOTE: Can accept a jQuery object as well as a string id.
	 */
	scrollTo: function(id) {
		if(typeof id == 'string')
			id = '#' + id;
		
		var offsetTop = $(id).offset().top;
		
		if($(window).scrollTop() > offsetTop + 50)
			$(window).scrollTop(offsetTop);
	},
	cycleDots: function(element) {
		element = $(element);
		var removeDots = function() {
			element.text(element.text().replace(/\.+$/, ''));
		};
		var addDot = function() { element.append('.'); };
		
		var lastThreeChars = element.text().substr(element.text().length - 3, 3);
		
		if(lastThreeChars == '...') removeDots();
		else addDot();
	}
});

$(function(){
	$.trackPage('UA-9026940-1');
	$('a').track({label: function($e){return $e.attr('title')}});
	$('button').track({label: function($e){return $e.parents('form').attr('action')}});
	
	// make any tabs on the page dynamic
	// TODO? could make this automatically happen on dom change and/or ajax response?
	$.skiclubz.initializeTabs();
	
	// keep a global collection of overlays
	$(document).bind('onBeforeLoad, onLoad', function(event) {
		var overlay = $(event.target).data('overlay');
		if(overlay)
			$.skiclubz.overlays[overlay.getOverlay().attr('id')] = overlay;
	});
	$(document).bind('onClose', function(event) {
		var overlay = $(event.target).data('overlay');
		if(overlay)
			delete $.skiclubz.overlays[overlay.getOverlay().attr('id')];
	});
	
	// sticky divs in asides should scroll with the viewport
	// this is used for video index buttons as of 3/14/11
	$('#aside .sticky').stickyPanel({
		topPadding: 10
	});

	// open an overlay onload if the location.hash matches the id of an element that triggers an
	// overlay. Currently only works if the id is the only thing in the hash to get around a bug
	// since upgrading to jQuery 1.4.4
	$(window).load(function() {
		if(location.hash.search(/^#[A-Za-z][A-Za-z0-9_:\.-]*$/) != -1 && $(location.hash).data('overlay')) {
			$(location.hash).data('overlay').load();
		}
	});

	// fix for overlays to allow close links/buttons/etc. inside AJAX-loaded content
	$('.overlay .close').live('click', function() {
		var overlay = $.skiclubz.overlays[$(this).closest('.overlay').attr('id')];
		if(overlay)
			overlay.close();
	});

	// allow ajax responses to set the "X-SkiClubZ-BrowserLocation" header to force a browser redirect
	$(document.body).ajaxComplete(function(event, xhr, ajaxOptions) {
		// redirect to the given url
		if(xhr) {
			if(xhr.getResponseHeader('X-SkiClubZ-BrowserLocation')) {
				document.location = xhr.getResponseHeader('X-SkiClubZ-BrowserLocation');
			} else if(xhr.getResponseHeader('X-SkiClubZ-OpenInBlank')) {
				// FIXME: this will trigger a "popup blocked" warning, maybe there's some better
				// way?
				window.open(xhr.getResponseHeader('X-SkiClubZ-OpenInBlank'));
			}
		}
	});
	
	// since the referer header isn't always reliable, set our own for Ajax requests
	$(document.body).ajaxSend(function(event, xhr, ajaxOptions) {
		xhr.setRequestHeader('X-SkiClubZ-Referer', document.location);
	});

	// yell at IE7 users --------------------------------------------
	
	if($.browser.msie && parseInt($.browser.version) < 8) {
		if(document.documentMode != undefined && document.documentMode < 8) {
			var message = '\
					<h2>Compatibility View Not Supported</h2>\
					<p>\
						Internet Explorer\'s <strong>Compatibility View</strong> is not supported by SkiClubZ. Please disable Compatibility View by going to the Tools menu and clicking the "Compatibility View" item. Please watch this <a href="http://www.youtube.com/watch?v=YSs1ulZKgCA">Internet Explorer 8 video</a> for more information.\
					</p>\
					<p>\
						Preferably, we recommend using <a href="http://google.com/chrome">Google Chrome</a> or <a href="http://apple.com/safari">Safari 4.0</a> or higher to get the best SkiClubZ video analysis experience, including keyboard shortcuts and overlays .\
					</p>';
		} else {
			var message = '\
					<h2>Browser Not Supported</h2>\
					<p>\
						<strong>Internet Explorer ' + parseFloat($.browser.version) + '</strong> is not supported by SkiClubZ. \
						Please upgrade your browser to one of the following:\
					</p>\
					<div class="browser-options">\
						<a class="btnalt" href="http://www.apple.com/safari/">\
							<img src="' + $.skiclubz.CDNBaseUrl + '/images/style/safari.png">\
							<br>\
							Safari\
						</a>\
						<a class="btnalt" href="http://google.com/chrome">\
							<img src="' + $.skiclubz.CDNBaseUrl + '/images/style/google-chrome.png">\
							<br>\
							Google Chrome\
						</a>\
						<a class="btnalt" href="http://microsoft.com/windows/internet-explorer">\
							<img src="' + $.skiclubz.CDNBaseUrl + '/images/style/internet-explorer.png">\
							<br>\
							Internet Explorer 8\
						</a>\
						<a class="btnalt" href="http://mozilla.com/firefox">\
							<img src="' + $.skiclubz.CDNBaseUrl + '/images/style/firefox.png">\
							<br>\
							Firefox\
						</a>\
					</div>\
					<div class="browser-experience">\
						 <strong>Best video analysis experience, including keyboard shortcuts and overlays</strong>\
					</div>';
		}
		
		$('body').prepend('\
			<div id="exposeMask"> </div>\
			<div class="overlay section" id="browserWarning">\
				<div class="in">\
					' + message + '\
				</div>\
			</div>\
		').find('#browserWarning').overlay({
			top: '30%',
			load: true // open immediately
		});
	}
	
	// --------------------------------------------------------------
	
	
	// event overlays -----------------------------------------------
	// these are done delegate-style to make them cooperate with ajax month paging

	// add event overlay for adding events from the calendars
	$('.calendar .add-event a[rel]').live('click', function(event) {
		$(this).overlay({
			top: '20%',
			load: true,
			// on load, insert date from day into popup
			onBeforeLoad: function(event){
				var overlay = this.getOverlay();
			
				// NOTE: "this" is the overlay object (different than normal jQuery event handlers)
				var day = this.getTrigger().parents('.day');
			
				// add the startDate to the form
				var dataDate = day.dataset('date');
				overlay.find('input.startDate').attr('value', dataDate);
			
				// display the startDate
				var prettyDate = day.attr('title');
				overlay.find('.startDate:not(input)').text(prettyDate);
			},
			onLoad: function() {
				// make sure the group tree select's control text is in sync with the selected
				// options
				this.getOverlay().find('.groupTreeSelect').updateText();
			},
			onClose: function() {
				// reset the form back to its defaults
				this.getOverlay().find('form')[0].reset();
			}
		});
		
		event.preventDefault();
	});
	
	// event summary overlay for showing event details from the calendar
	$('.calendar .events a[rel]').live('click', function(event) {
		$(this).overlay({
			top: '20%',
			load: true,
			// on load, perform ajax request to load event data
			onBeforeLoad: function() {
				// NOTE: "this" is the overlay object (different than normal jQuery event handlers)
				var event = this.getTrigger();
				var overlay = this.getOverlay();
			
				$.skiclubz.eventToCopy = event.dataset();

				// go through data attributes on event and fill in values
				// in overlay for elements with matching class names
				// (eg data-location gets put into elements with class="location")
				// because case-sensitivity varies between browsers, the class 
				// names should always be in lowercase
				$.each(event.dataset(), function(name, value) {
					var element = overlay.find('.' + name.toLowerCase());
					if(element.size()) {
						if(value) element.removeClass('null').text(value);
						else element.addClass('null').text('Not Set');
					}
				});
			
				// set the view link url
				overlay.find('a.view').attr('href', event.dataset('viewUrl'));
			
				// set the edit link url (and hide/show as needed)
				var editUrl = event.dataset('editUrl');
				var editLink = overlay.find('a.edit');
				if(editUrl) editLink.show().attr('href', editUrl);
				else editLink.hide();
			}
		});
		
		event.preventDefault();
	});
	
	// --------------------------------------------------------------
	
	
	// copy/paste ---------------------------------------------------
	
	$('.copy').click(function() {
		$.skiclubz.copiedEvent = $.skiclubz.eventToCopy;
		delete $.skiclubz.copiedEvent.startdate; // don't copy the date
		delete $.skiclubz.copiedEvent.startDate; // damnit, IE
		$.skiclubz.copiedEvent.attendees = $.parseJSON($.skiclubz.copiedEvent.attendees); // turn the attendees into an actual array to make it easier to work with
		$('.paste').show();
		$.skiclubz.overlays.eventsummary.close(); // close the overlay
	});
	
	// the below assumes there is only one event form on the page (safe?)
	$('.paste').click(function(event) {
		event.preventDefault();
		
		// match input names to the attribute (needs to be 
		// case-insensitive because of browser inconsistencies)
		var findInput = function(attribute) {
			var name = 'Event[' + attribute + ']';
			return $('input, select').filter(function() {
				var lowercaseAttribute = $(this).attr('name').toLowerCase();
				return lowercaseAttribute.indexOf(name.toLowerCase()) != -1;
			});
		};
		
		// add attributes in copiedEvent into their corresponding inputs
		$.each($.skiclubz.copiedEvent, function(name, value) {
			var input = findInput(name);
			if(input) input.val(value);
		});
		
		// save the current group inputs and set up an event handler to restore them on close
		var groupInputs = $('.control.attendees');
		$.skiclubz.overlays.createevent.getTrigger().one('onClose', function(){
			// restore the groupInputs if needed
			if($('#createevent').data('missingGroups')) {
				$('#createevent').find('.control.attendees').replaceWith(groupInputs);
				$('#createevent').data('missingGroups', false);
			}
		});
		
		// detach the current group inputs & replace with a new .control.attendees div
		groupInputs.after('<div class="control attendees"><label class="list-label">Attendees</label></div>').detach();
		$('#createevent').data('missingGroups', true);
		
		// say how many people are invited
		var invited = $.skiclubz.copiedEvent.attendees.length;
		if(invited == 1) invited += ' person';
		else invited += ' people';
		$('.control.attendees').append('<p>' + invited + '</p>');
		
		// insert inputs with attendee data
		$.each($.skiclubz.copiedEvent.attendees, function(index, attendeeId) {
			$('.control.attendees').append('<input type="hidden" name="Event[attendees][]" value="' + attendeeId + '">');
		});
	});
	$('.paste').hide(); // hide the paste link onload (we'll show it if something gets copied)
	
	// --------------------------------------------------------------
	
	
	// event summary popup for showing event details from the calendar
	$("a[rel].eventinvite").overlay({
		top: '20%'
	});
	
	// currently unimplemented overlay for managing videos from an event
	// $("a[rel].eventvideo").overlay({
	// 	top: '20%'
	// });
	
	// group invite overlays ----------------------------------------
	
	$(".group-view a[rel].invite").overlay({
		top: '20%',
		onBeforeLoad: function() {
			var form = this.getOverlay().find('div.form');
			
			form.html('Loading...');
			form.load(this.getTrigger().attr('href'), function() {
				form.find('.treeview-section ul').treeview({});
			});
		},
		onLoad: function() {
			var overlay = this.getOverlay();
			overlay.find('textarea:visible:first').focus();
		}
	});
	
	$('#groupinvite button[type=submit]').live('click', function(evt) {
		evt.preventDefault();
		// TODO:
			// validate after confirm
				// would have to switch back to the original form if validation failed
				// & copy the id of the new group to the original form
		
		var confirmFormDiv = undefined;
		var inviteFormDiv = $(this).closest('.overlay').find('div.inviteWrapper');
		
		if($(this).attr('rel') && (confirmFormDiv = $($(this).attr('rel')).find('div.form'))) {
			confirmFormDiv.css('display', 'none');
			
			inviteFormDiv.parent().append(confirmFormDiv);
			inviteFormDiv.fadeOut(function() {
				confirmFormDiv.fadeIn();
				
				confirmFormDiv.find("input:radio:enabled:visible:first").attr("checked", true);
				
				// add the form from the inviteFormDiv to the confirmFormDiv so we can submit stuff
				// together! whee
				$('<div class="inviteForm"> </div>')
					.css('display', 'none')
					.append(inviteFormDiv.find('form > *'))
					.appendTo(confirmFormDiv.children('form'));
			});
		} else {
			var form = $(this).parents('form').get(0);
			
			// FIXME: check for a checked checkbox or email address before submitting
			$.ajax({
				url: form.action,
				context: form,
				data: $(form).serialize(),
				type: 'POST',
				success: function(data) {
					$(form).closest('.overlay.section').find('.form').html(data);
				},
				error: function(xhr) {
					confirmFormDiv = $(this).closest('div.form.confirm');
					
					var errorType = xhr.getResponseHeader('X-SkiClubZ-ErrorType');
					if(errorType && errorType == 'Not-Allowed' && confirmFormDiv.length) {
						if(xhr.responseText) {
							$('.errorMessage', confirmFormDiv).html(xhr.responseText).css('display', 'block');
						}
					} else {
						if(xhr.responseText) {
							$('.errorMessage', inviteFormDiv).html(xhr.responseText).css('display', 'block');
						}
						
						if(confirmFormDiv.length) {
							// move the form stuff from div.inviteForm back to the real invite form
							$('div.inviteForm', confirmFormDiv).children().appendTo(inviteFormDiv.children('form'));
							
							confirmFormDiv.fadeOut(function() {
								inviteFormDiv.fadeIn();
								
								// make it so that you don't go back to the confirm form once you
								// fix the validation errors
								inviteFormDiv.find('button[type=submit]').removeAttr('rel');
							});
						}
					}
				}
			});
		}
		
		return false;
	});
	
	// --------------------------------------------------------------
	
	// expanders (e.g. group/_inviteuser) ---------------------------
	
	$('.expander').live('click', function() {
		$($(this).attr('rel')).slideToggle();
		
		// this only happens if one of these classes is set to start,
		// so if you don't want the images don't use them
		if($(this).hasClass('open'))
			$(this).removeClass('open').addClass('closed');
		else if($(this).hasClass('closed'))
			$(this).removeClass('closed').addClass('open');
		
		return false;
	});
	
	// --------------------------------------------------------------
	
	// switch group invite type [email vs. existing users] ----------
	
	$('#switchInviteType').live('click', function() {
		var parent = $(this).parents('#groupinvite');
		var athletes = $('.athletes', parent),
			email = $('.email', parent),
			link = $(this);
		
		if(athletes.css('display')=='none') {
			// hide email, show athletes
			email.fadeOut(function() {
				athletes.fadeIn();
				link.text('Or enter email addresses to invite');
			});
		} else {
			// hide athletes, show email
			athletes.fadeOut(function() {
				email.fadeIn();
				link.text('Or select users to invite');
				$('textarea:visible:first', email).focus();
			});
		}
	});
	
	// --------------------------------------------------------------
	

	
	$('.date-ago').timeago();
	$(document).ajaxComplete(function() { $('.date-ago').timeago(); });
	
	$('a.delete-comment').live('click', function(){
		var answer = confirm("Are you sure you want to delete this comment?");
		if (answer){
			var form = $(this).parents('form');
			$.ajax({
				'url': form.attr('action'),
				'data': form.serialize(),
				'type': 'POST',
				'context': form.parents('.item'),
				
				'success': function(data) {
					$(this).remove();
					var numCommentsDiv = $("#comment-list > em div");
					var numComments = numCommentsDiv.text().split(" ");
					var num = 0;
					if(numComments.length>1) {
						num = --numComments[0];
						if(num==0)
							numCommentsDiv.remove();
						else
							numCommentsDiv.text(num + " " + numComments[1]);
					}
					
					if(!num) {
						var empty = $('#comment-list .items .empty');
						if(empty.length) {
							empty.show();
						} else {
							empty = $('<span class="empty">Be the first to comment!</span>');
							$('#comment-list .items').prepend(empty);
						}
					}
				}
			});
		}
		
		return false;
	});
	
	// set up event handlers for video form to load athletes who the video can be assigned to
	// save this so we can call it again to reset handlers after ajax changes the form
	// NOTE: This works in IE8 since at least jQuery 1.4.2.
	$('select.eventId, select.groupId').live('change', function() {
		var form = $(this).closest('form');
		
		$.ajax({
			url: $.skiclubz.baseUrl + '/group/ajaxGetAthletes',
			data: {id: $('select.groupId', form).val(), eventId: $('select.eventId', form).val()},
			success: function(data) {
				var selectBox = form.find('select.assigneeId');
				var selected = $('option:selected', selectBox).val();
				
				// clear the athletes and insert new ones (including one for "Unassigned")
				selectBox.empty();
				selectBox.append('<option value="0">Unassigned</option>');
				if(data.athletes.length != 0) {
					$.each(data.athletes, function(id, name) {
						var option = $('<option value="' + id + '">' + name + '</option>');
						if(id == selected) option.attr('selected', 'selected');
						selectBox.append(option);
					});
				}
				
				// if an event was successfully selected
				if(data.event) {
					// set type/discipline to that of the selected event
					if(data.event.disciplineId)
						form.find('select.disciplineId').val(data.event.disciplineId);
					if(data.event.typeId)
						form.find('select.typeId').val(data.event.typeId);
				
					// disable type/discipline
					form.find('select.disciplineId').attr("disabled", "disabled");
					form.find('select.typeId').attr("disabled", "disabled");
				} else {
					// enable type/discipline
					form.find('select.disciplineId').removeAttr("disabled");
					form.find('select.typeId').removeAttr("disabled");
				}
			}
		});
	});

	$('#aside .video-form').live('submit', function(e) {
		if(!$(this).data('validated')) {
			e.preventDefault();

			var pk = $.skiclubz.stripNonNumeric($(this).attr('id'));
			
			$.ajax({
				// get the id out of the first input element
				url: $.skiclubz.baseUrl + '/video/update/',
				type: 'POST',
				data: $(this).serialize() + '&ajax=video-form',
				dataType: 'json',
				context: this,

				success: function(data) {
					$(this).data('validated', true);
					$(this).find('.errorMessage').hide();
					$(this).submit();
				},

				error: function(xhr) {
					try {
						var response = $.parseJSON(xhr.responseText),
							el = this;
						
						$.each(response[pk], function(key, value) {
							$(el).find('#Video_' + pk + '_' + key + '_error').text($(this).get(0));
						});
					} catch (err) {
						$(this).find('#Video_' + pk + '_id_error').html(xhr.responseText);
					}

					$(this).data('validated', false);
				}
			});
		}
	});

	$('.edit-video').live('click', function() {
		$('.info').hide();
		$('.meta .avatar').hide();
		
		$('.claim').hide();
		
		$('.video-form').show();
		$('.cancel-edit-video').show();
		$(this).hide();
		// ^ = $('.edit-video').hide();
		
		return false;
	});
	
	$('.cancel-edit-video').live('click', function() {
		$('.info').show();
		$('.meta .avatar').show();
		
		$('.claim').show();
		
		$('.video-form').hide();
		$('.edit-video').show();
		$(this).hide();
		// ^ = $('.cancel-edit-video').hide();
		
		return false;
	});
	
	// it would be nice if we could use the submit event for this, but 
	// IE doesn't propogate those correctly
	$('.claim .btn').live('click', function(e) {
		e.preventDefault();

		var form = $(this).closest('form')
			pk = $.skiclubz.stripNonNumeric($(this).attr('id')),
			select = form.find('select[name="groupId"]'),
			extra = 'aside';
		
		if($(this).closest('.items').hasClass('organize'))
			extra = 'form';
		
		$.ajax({
			url: form.attr('action'),
			type: form.attr('method'),
			data: { groupId: select.val(), getExtra: extra },
			dataType: 'json',
			context: this,

			success: function(data, status, xhr) {
				var button = $(this),
					label = form.find('label');
				
				if(data.done) {
					// update the title and aside to reflect the claimed video state
					// also need to re-initialize some javascript associated with this
					if(data.title) $('.video-detail .title').text(data.title);

					if(data.aside) {
						$('#aside').replaceWith(data.aside);
						$.skiclubz.initializeTabs();
					}

					// server returned new attributes for the video, so put them in
					if(data.form) {
						var item = form.closest('.item'),
							editForm = item.find('.video-form');
						
						if(editForm.size()) {
							editForm.replaceWith(data.form);
						} else {
							item.find('.meta').prepend(data.form);
							editForm = item.find('.video-form');
						}

						editForm.fadeIn();
						item.find('.info').fadeOut();

						// trigger a saved event with no attributes to trick organizeVideos.js into
						// making this look saved.
						var attributes = {};
						attributes[pk] = {};
						item.trigger('saved', attributes);

						// disable the inputs manually
						editForm.find('input[type!="submit"], select').each(function() {
							$(this).attr('disabled', 'disabled');
						});

						if(data.success) {
							item.prepend('<div class="success">' + data.success + '</div>');
							delete data.success;
						}
					}
				} else {
					// the user has to choose what group the video should belong to (there was some ambiguity)
					var options = select.attr('options');
					
					for(var group in data.data) {
						var option = document.createElement('option');
						option.value = group;
						option.text = data.data[group];
				
						var oL = options.length;
						options[oL] = option;
					}
					
					label.text(data.prompt);
					select.show();
					label.show();
					button.val('Save Changes');
				}
				
				$.skiclubz.flash(data);
			},

			error: function(xhr) {
				$.skiclubz.flash(xhr.responseText, 'error');
			}
		});
	});
				
	// --------------------------------------------------------------
	
	$('#Group_allowsAthletes').live('click', function(event) {
		if(!$(this).attr('checked')) {
			var answer = confirm('Warning: this will disallow any user from joining the group as an athlete. If there are any athletes in this group they will be removed.');
			if(!answer) {
				$(this).attr('checked', true);
			}
		}
	});
	
	$('.cancel-button').click(function(){
		var answer = confirm("Are you sure you want to cancel this?")
		if (answer){
			$(this).parents('form').submit();
		}
		else
		{
			return false;
		}
	});

	$('#inviteuser select[name=groupFilter]').change(function(){
		var groupId = $(this).find('option:selected').attr('value');
		if(groupId == 'all') $('#inviteuser .user').show(); // show all
		else {
			$('#inviteuser .user').hide(); // hide all
			$('#inviteuser .user [data-group' + groupId + ']').parents('.user').show(); // show only users in this group
		}
	});
	
	// uploader remember selection

	$('.uploadMenu ul li a').live('click', function(event) {
		var uploadMenu = $(event.target).closest('.uploadMenu');
		var remember = uploadMenu.find('.remember input').first();
		
		if(remember && remember.attr('checked')) {
			event.target.href += "/save/true";
		}
		
		return true;
	});
	
	// dashboard view all pending requests/invitations
	$('#requests .requestitem .countLink').live('click', function(event) {
		var requestitem = $(this).closest('.requestitem');
		requestitem.find('.userList').slideToggle();
		return false;
	});
	
	// autogenerate event titles ------------------------------------
	
	var autogenerateName = function() {
		// check if the event name currently matches any disciplines (or is empty)
		var updateName = !$('#Event_name').val();
		
		// update event name if it is currently set to a discipline
		// FIXME: is there a shorter way to accomplish this?
		$('#Event_disciplineId option').each(function(index, value) {
			if(updateName) return false; // break out of each
			else updateName = ($(value).text() == $('#Event_name').val());
		});
		
		if(updateName) $('#Event_name').val($('#Event_disciplineId option:selected').text());
	};
	$('#Event_disciplineId').change(autogenerateName);
	if($('#Event_name')) autogenerateName(); // autogenerate onload
	
	// --------------------------------------------------------------
	
	
	// inviteuser overlay -------------------------------------------
	
	// works around some IE bugs related to cloning inputs
	// this will probably only work if the elements themselves are 
	// inputs (eg cloning an entire form will not work)
	// NOTE: only the "checked" attribute correction has been tested 
	//       thoroughly, but the other attributes should work
	$.fn.inputClone = function(events) {
		this.each(function() {
			this.setAttribute('value', this.value);
			
			if(this.checked) this.setAttribute('checked', 'checked');
			else this.removeAttribute('checked');
			
			if(this.selected) this.setAttribute('selected', 'selected');
			else this.removeAttribute('selected');
		});
		return this.clone(events);
	};
	
	$('#inviteuser *[type=submit]').click(function(event){
		event.preventDefault(); // don't actually submit
		
		// copy attendee checkboxes to event form
		$('#event-form .attendees-placeholder').html($('#inviteuser input.attendee').inputClone());
		
		// update the button text to say how many people were invited
		$('a[rel].eventinvite').text($('#inviteuser .invited-count').text());
		
		// close the overlay
		$('a[rel].eventinvite').data('overlay').close();
	});
	
	// these next few event handlers take care of the invited count 
	// and select all input on the #inviteuser overlay
	var updateInvitedCount = function(event, context){
		if(!context) context = $(this).parents('form');
		
		// update .invited-count with the total number of checked users
		var invited = $('.user input.attendee:checked', context).length;
		if(invited == 1) invited += ' person';
		else invited += ' people';
		$('.invited-count', context).text(invited);
	};
	$('#inviteuser .user input.attendee, #groupinvite .user input.attendee').live('click', updateInvitedCount);

	// check all visible attendees when the select all checkbox is checked (and uncheck all when not)
	$('#inviteuser input[name=select-all-attendees]').change(function(event){
		var context = $(this).parents('form');
		$('input.attendee:visible', context).attr('checked', this.checked);
		updateInvitedCount(event, context);
	});

	// keep select all in sync with the rest of the inputs
	var syncSelectAll = function(event){
		var context = $(this).parents('form');
		// if all attendee checkboxes are checked, then also check the select all box
		var allAreChecked = !$('input.attendee:visible:not(:checked)', context).length;
		$('input[name=select-all-attendees]', context).attr('checked', allAreChecked);
		updateInvitedCount(event, context);
	};
	$('#inviteuser input.attendee').change(syncSelectAll);
	if($("a[rel].eventinvite").data('overlay')) {
		$("a[rel].eventinvite").data('overlay').onLoad(syncSelectAll);
	}
	if($(".group-view a[rel].invite").data('overlay')) {
		$(".group-view a[rel].invite").data('overlay').onLoad(syncSelectAll);
	}
	
	
	// --------------------------------------------------------------
	
	
	// create event overlay handlers --------------------------------
	
	// make sure we submit normally from the advanced button
	$('#createevent form [name=goToAdvanced]').click(function() {
		$('#createevent form').data('goToAdvanced', true);
	});
	$('#createevent form').submit(function(event) {
		var form = $(this);
		if(!form.data('goToAdvanced')) { // don't do anything if the user clicked the advanced button
			// disable the submit button when it is clicked, and re-enable it when the overlay closes
			var submit = form.find('[type=submit]');
			submit.attr('disabled', 'disabled');
			$.skiclubz.overlays.createevent.onClose(function(){ submit.removeAttr('disabled'); });
			
			event.preventDefault();
			var postData = form.serialize();
			$.post(
				form.attr('action'),
				postData,
				function(data, status, request) {
					$.skiclubz.overlays.createevent.close();
					$.fn.yiiBBQListView.update($('.calendar-view').attr('id')); // reload the calendar
				}
			);
		}
	});
	
	// --------------------------------------------------------------
	
	
	// toggle events shown on dashboard -----------------------------
	
	$('.toggle-events').click(function(){
		$('.toggle-events').removeClass('selected');
		$(this).addClass('selected');
		$('.events').hide();
		$('.' + $(this).dataset('events')).show();
		
		return false;
	});
	
	$('.toggle-videos').click(function(){
		$('.toggle-videos').removeClass('selected');
		$(this).addClass('selected');
		$('.videos').hide();
		$('.' + $(this).dataset('videos')).show();
		
		return false;
	});
	
	// --------------------------------------------------------------
	
	// group invite button on user/view -----------------------------
	$('.groupInviteLink').live('click', function() {
		$(this).closest('.groupInvite').find('ul').slideToggle('fast');
		$('.groupInviteLink.btnalt').toggle(50);
		return false;
	});
	// --------------------------------------------------------------
	
	// cascading selects in video filters ---------------------------
	
	/* TODO?
		- maybe we should namespace this and other helpers with "skiclubz" to avoid conflicts
		  (e.g. $('select').skiclubz.insertOptions(...))
			- will jquery like this?
		- use this in the welcome js as well
	*/
	$.fn.insertOptions = function(data) {
		var element = this;
		$.each(data, function(index, value) {
			element.append('<option value="' + index + '">' + value + '</option>');
		});
	};
	
	// save some things related to the assignee control to make life easier
	var assigneeSelect = $('select.assignee.cascading');
	var assigneeControl = assigneeSelect.parents('.control');
	var clearAssigneeControl = function() {
		// remove all except prompt
		assigneeSelect.children().detach(':not(.prompt)');
		assigneeControl.hide();
	};
	
	$('select.cascading.organizations').change(function() {
		// load athletes into the assignee select
		$.ajax({
			url: $.skiclubz.baseUrl + '/group/ajaxGetAthletes',
			data: {id: $(this).val(), includeDescendants: true},
			success: function(data) {
				clearAssigneeControl();
				if(data.athletes) {
					assigneeControl.show();
					assigneeSelect.insertOptions(data.athletes);
				}
			},
			error: clearAssigneeControl
		});
	});
	
	// --------------------------------------------------------------
	
	// show more notifications --------------------------------------
	
	$.skiclubz.notificationsShown = $('#notifications ul.top-level > li').length;
	$('#notifications .show-more').click(function() {
		// set up and run a busy animation (animate the ellipsis)
		var doAnimation = setInterval(function(){ $.skiclubz.cycleDots($('#notifications .show-more')); }, 500);
		
		// load more notifications
		// the current setup shows X more where X is the number of notifications shown on page load
		// we have to tell the server to start from the last notification currently shown (offset)
		$.ajax({
			data: {limit: $.skiclubz.notificationsShown, offset: $('#notifications ul.top-level > li').length, id: $.skiclubz.user.id},
			url: $.skiclubz.baseUrl + '/user/showMoreNotifications',
			success: function(data) {
				$('#notifications hr').show(); // show the hr in case it's been hidden by the .hide-notification handler
				$('#notifications ul.top-level').append(data.html);
				if(data.end) {
					$('#notifications .show-more').replaceWith('All Notifications Shown');
				}
				
				// stop the busy animation and reset the ellipsis
				// TODO? do this on complete/error instead of success?
				clearInterval(doAnimation);
				$('#notifications .show-more').text($('#notifications .show-more').text().replace(/\.+$/, ''));
				$('#notifications .show-more').append('...');
			}
		});
	});
	
	// --------------------------------------------------------------
	
	
	// accept/decline notifications -------------------------------------------
	
	$('#notifications .finalize-pending-relationship').live('click', function() {
		var button = $(this);

		var createRelationship = button.dataset('createrelationship');
		$.ajax({
			url: $.skiclubz.baseUrl + '/user/respondToRequestOrInvitation/' + $.skiclubz.user.id,
			data: { pendingRelationshipId: button.dataset('pendingrelationshipid'), createRelationship: createRelationship, notificationId: button.dataset('notificationid') },
			type: 'post',
			success: function(data) {
				$.skiclubz.replaceFlash(data);
				
				// hide this notification if everything worked
				// by making it look like a hide button and triggering a click event
				button.removeClass('finalize-pending-relationship').addClass('hide-notification').click();
			},
			error: function(xhr) {
				if(!xhr.getResponseHeader('X-SkiClubZ-BrowserLocation')) {
					var body = xhr.responseText.trim();
					if(body == "") {
						body = "There was an error accepting the relationship.";
					}
					
					// show the error response in an overlay
					$('body').prepend('\
						<div class="overlay section" id="browserWarning">\
							<a class="close closex">close</a>\
							' + body + '\
						</div>\
					').find('#browserWarning').overlay({
						top: '30%',
						load: true // open immediately
					});
				}
			}
		});
	});
	
	
	// hide notifications -------------------------------------------
	
	$('#notifications .hide-notification').live('click', function() {
		$.ajax({
			url: $.skiclubz.baseUrl + '/user/hideNotification/' + $.skiclubz.user.id,
			data: { notificationId: $(this).dataset('notificationid') },
			type: 'post',
			success: function(data) {
				var hiddenNotification = $('.notification-' + data.notificationId);
				
				// if this was the last notification in a group, ditch the whole group
				if(hiddenNotification.closest('li.group').length != 0 && hiddenNotification.siblings().length == 0) {
					hiddenNotification.closest('li.group').remove();
				} else {
					hiddenNotification.remove(); // otherwise just ditch this notification
				}
				
				// if this was the last notification, hide the entire section
				if($('#notifications ul.top-level li').length == 0) {
					if($('#notifications .show-more').length == 0) { // only hide it if the show more link is not present
						$('#notifications').hide();
					} else { // need to hide just the hr otherwise
						$('#notifications hr').hide();
					}
				}
			}
		});
	});

	// --------------------------------------------------------------
		
	
	// hide pending relationships -----------------------------------
	
	$('#pending-relationships .hide-pending-relationship').live('click', function() {
		$.ajax({
			url: $.skiclubz.baseUrl + '/user/hidePendingRelationship/' + $.skiclubz.user.id,
			data: { pendingRelationshipId: $(this).dataset('pendingrelationshipid') },
			type: 'post',
			success: function(data) {
				$('.pending-relationship-' + data.pendingRelationshipId).remove();
				
				// if this was the last pending relationship, hide the entire section
				if($('#pending-relationships ul.top-level li').length == 0) {
					$('#pending-relationships').hide();
				}
			}
		});
	});
	
	// --------------------------------------------------------------
	
	
	// show notification group --------------------------------------
	
	$('#notifications .group-control').live('click', function() {
		$(this).next('ul').show();
		$(this).remove();
	});

	// --------------------------------------------------------------
	
	
	// notification overlay -----------------------------------------
	
	$('#notificationsOverlay').overlay({
		load: true,
		top: '30%'
	});

	// --------------------------------------------------------------
	
	
	
	
	// new club page ------------------------------------------------
	$('#NewClubForm_orgName').change(function() {
		$('.replaceOrgName').text($(this).val());
	});
	$('#NewClubForm_orgDesc').change(function() {
		$('.replaceOrgDesc').text($(this).val());
	});
	
	var saveAndToggleText = function(e) {
		var key = $(this).attr('name'),
			val = $(this).val();
		if (e.type=='focus') {
			if(typeof saveAndToggleText[key] == 'undefined') {
				saveAndToggleText[key] = val;
				$(this).val('');
			} else if(val==saveAndToggleText[key]) {
				$(this).val('');
			}
		} else if(val=='' && typeof saveAndToggleText[key] != 'undefined') {
			$(this).val(saveAndToggleText[key]);
		}
	}
	
	$('#NewClubForm_orgDesc').focus(saveAndToggleText);
	$('#NewClubForm_orgDesc').blur(saveAndToggleText);

	
	$('#page2Submit').click(function() {
		if(!$('#certifyUnderstood').attr('checked') || !$('#agreeToTerms').attr('checked')) {
			// error...
			var understood = $('#certifyUnderstood');
			if(!understood.attr('checked')) {
				var em = understood.closest('label').siblings('.errorMessage');
				
				if(!em.length) {
					em = $('<div class="errorMessage"></div>');
					em.appendTo($(understood.closest('div')));
				}
				
				em.text('You must certify that you have the authority to execute the Club Engagement Letter.');
				em.show();
			} else {
				understood.closest('label').siblings('.errorMessage').hide();
			}
			
			var agree = $('#agreeToTerms');
			if(!agree.attr('checked')) {
				var em = agree.closest('label').siblings('.errorMessage');
				
				if(!em.length) {
					em = $('<div class="errorMessage"></div>');
					em.appendTo($(agree.closest('div')));
				}
				
				em.text('You must agree to the terms of the Club Engagement Letter.');
				em.show();
			} else {
				agree.closest('label').siblings('.errorMessage').hide();
			}
			
			return false;
		}
		
		return true;
	});
	
	// --------------------------------------------------------------
	
	// Java Uploader popups -----------------------------------------
	$('.uploaderLink').click(function() {
		var href = $(this).attr('rel');
		
		$.skiclubz.checkJavaCompatibility(function() {
			href += href.indexOf('?') == -1 ? '?' : '&';
			window.open(
				href + 'popup=true', 
				'Uploader', 
				'status=no,toolbar=no,location=no,menubar=no,directories=no,resizable=yes,scrollbars=no,height=' + (screen.availHeight - 100) + ',width=940'
			);
		});
		return false;
	});
	// --------------------------------------------------------------
	
	
	// splash page slideshow ----------------------------------------

	// run the slideshow at a 5 second interval
	// loop back to the first one when done
	$(function() {
		var slideshowInterval = setInterval(function() {
			var current = $('.why:visible');
			
			// clear the interval if we're not on the splash page so we're not wasting resources
			if(current.length == 0) clearInterval(slideshowInterval);
			
			var next = current.next('.why').length ? current.next() : $('.why:first');
			current.fadeOut('slow', function() { next.fadeIn('slow') });
		}, 5000);
	});	
	
	// --------------------------------------------------------------


	// screenshot gallery on the features page ----------------------

	// keep this stuff "private" to avoid potential conflicts
	(function() {
		if($('.feature-thumb').length > 0) {
			// preload the large images
			$('.feature-thumb').each(function(index, link) { $.skiclubz.preloadImage($(link).attr('href')); });
		
			// shows the given image
			// should be passed an element with an href attribute pointing to 
			// the large image and a title attribute with the caption
			var showImg = function(link) {
				if(link.data('overlay')) {
					var overlay = link.data('overlay').getOverlay();
				
					// image
					var src = $(link).attr('href');
					overlay.find('img').attr('src', src);
				
					// caption
					var caption = $(link).attr('title');
					overlay.find('.caption').text(caption);
				} else if(link.href) {
					// the overlay failed to open for some reason, just redirect to the image instead
					window.location = link.href;
				}
			};
			var next = function() {
				var currentSrc = $('#feature-gallery img').attr('src');
				var current = $('a.feature-thumb[href=' + currentSrc + ']');
				var next = current.next('.feature-thumb').length ? current.next() : $('.feature-thumb:first');
				showImg(next);
			};
			var previous = function() {
				var currentSrc = $('#feature-gallery img').attr('src');
				var current = $('a.feature-thumb[href=' + currentSrc + ']');
				var previous = current.prev('.feature-thumb').length ? current.prev() : $('.feature-thumb:last');
				showImg(previous);
			};
		
			// show the clicked-on image when opening the overlay
			$('.feature-thumb').overlay({
				top: '20%',
				onBeforeLoad: function(event) {
					showImg(this.getTrigger());
				}
			});
		
			// pressing left or clicking on the previous link shows the 
			// previous image
			$(document).bind('keydown', 'left', previous);	
			$('#feature-gallery .previous').click(previous);
		
			// pressing right, clicking on the image, or clicking on the next 
			// arrow shows the next image
			$(document).bind('keydown', 'right', next);
			$('#feature-gallery .next, #feature-gallery img').click(next);
		}
	})();
	
	// --------------------------------------------------------------

	
	// elements with class "submitForm" will use yii's submitForm method
	// (similar to CHtml::linkButton()), passing parameters from data attributes
	// NOTE: you must include the yii jquery plugin to use this! (via ->registerCoreScript('yii'))
	$('.submitForm').live('click', function(event) {
		// if there is data-confirm attribute then make sure the user confirms
		if(!$(this).dataset('confirm') || confirm($(this).dataset('confirm'))) {
			$.yii.submitForm(
				this,
				$(this).dataset('submit') || $(this).attr('href'), // prefer a data-submit attribute but fall back to href
				$.parseJSON($(this).dataset('params')) || {} // params must be a JSON string if present
			);
		}
		event.preventDefault();
	});
	// --------------------------------------------------------------
	
	
	//controls for toggling visibility of the advanced options pane in the filter bar
	$('#advancedOptionsShow').live('click', function(event) {
		$('#shownOrHidden').val('show');
		$('#advancedOptionsShow').toggle();
		$('#advancedOptionsHide').toggle();
		$('#advancedOptions').toggle('fast');
	});
	
	$('#advancedOptionsHide').live('click', function(event) {
		$('#shownOrHidden').val('hide');
		$('#advancedOptionsShow').toggle();
		$('#advancedOptionsHide').toggle();
		$('#advancedOptions').toggle('fast');
		//$('input[id=showEventsWithVideos]').attr('checked', false); //uncheck boxes if user hides options
		$('input[id=showOnlyUnassigned]').attr('checked', false);
		//$('input[name=showUploadedBetween]').attr('checked', false);
		//$('#filterSubmit').click();
	});
	
	//show/hide notifications on dashboard
	
	$('#hideN').live('click', function(event) {
		$('#toggleN').toggle();
		$('#notificationCount').toggle();
		$('#hideN').toggle();
		$('#showN').toggle();
	});
	
	$('#showN').live('click', function(event) {
		$('#toggleN').toggle();
		$('#notificationCount').toggle();
		$('#showN').toggle();
		$('#hideN').toggle();
	});
	
	//show/hide pending relationships on dashboard
	
	$('#hideP').live('click', function(event) {
		$('#toggleP').toggle();
		$('#pendingCount').toggle();
		$('#hideP').toggle();
		$('#showP').toggle();
	});
	
	$('#showP').live('click', function(event) {
		$('#toggleP').toggle();
		$('#pendingCount').toggle();
		$('#showP').toggle();
		$('#hideP').toggle();
	});
	
	
	// AJAX splitscreen links ---------------------------------------
	
	$('.splitscreen.add').live('click', function(e) {
		// don't do anything for links that don't point anywhere!
		if($(this).attr('href') == '#')
			return false;

		// don't do anything for the second splitscreen video or if we're already loading
		if($(this).hasClass('second'))
			return true;
		else if($('.splitscreen.add').hasClass('loading'))
			return false;
		
		e.preventDefault();
		
		// add the loading class
		$(this).addClass('loading');
		
		// do the ajax request
		$.ajax({
			context: this,
			url: $(this).attr('href'),
			dataType: 'html',
			success: function(html) {
				// add the video-for-splitscreen html from the server
				$('#flashes').after(html);
				
				// change link to remove from splitscreen link
				var link = $(this).attr('href'),
					split = link.split('/');
				$(this).removeClass('add').addClass('remove')
					.attr('href', $.skiclubz.baseUrl + '/video/splitscreen.clear/' + split[split.length - 1])
					.text('Remove from splitscreen')
					.removeClass('loading');
				
				// change all other add to splitscreen links to target="_blank" and add
				// " (second video)" to the link text
				$('.splitscreen.add').attr('target', '_blank').addClass('second').each(function() {
					$(this).text($(this).text().replace(' (second video)', '') + ' (second video)');
				});
			},
			error: function(xhr) {
				var message = $('<div class="error section" />').html(xhr.responseText);
				$('#flashes').empty().append(message);
				$(window).scrollTop($('#flashes').offset().top);
			}
		});
	});
	
	$('.splitscreen.remove').live('click', function(e) {
		e.preventDefault();
		
		// do the ajax request
		$.ajax({
			context: this,
			url: $(this).attr('href'),
			dataType: 'html',
			success: function(html) {
				// remove the video-for-splitscreen block
				$('.video-for-splitscreen').remove();
				
				// change any remove from splitscreen link back to add to splitscreen link (may 
				// not be the link clicked on!)
				$('.splitscreen.remove').each(function() {
					var link = $(this).attr('href'),
						split = link.split('/');
					
					$(this).removeClass('remove').addClass('add')
						.attr('href', $.skiclubz.baseUrl + '/video/splitscreen.add/' + split[split.length - 1])
						.text('Add to splitscreen');
				});
				
				// change all other add to splitscreen links to target="" and remove
				// " (second video)" from the link text
				$('.splitscreen.add').removeAttr('target').removeClass('second').each(function() {
					$(this).text($(this).text().replace(' (second video)', ''));
				});
			},
			error: function(xhr) {
				var message = $('<div class="error section" />').text(xhr.responseText);
				$('#flashes').empty().append(message);
				$(window).scrollTop($('#flashes').offset().top);
			}
		});
	});
	
	// --------------------------------------------------------------
	
	$('#eventFilters').submit(function() {
		var filters = $.deparam($(this).serialize());
		filters['ajax'] = $('.calendar-view').attr('id');
		$.bbq.pushState(filters, 0);
		return false;
	});

	$('.remove.video').live('click', function(e) {
		e.preventDefault();
		
		if($(this).attr('data-submit') && confirm('Are you sure you want to delete this video?')) {
			jQuery.yii.submitForm(this, $(this).attr('data-submit'), {});
		}
	});
});

