function getProfileInfo(uid, callback) {
	FB.api({
		method:"fql.query", 
		query:"select name, email, first_name, last_name, birthday_date, sex from user where uid="+uid
		}, function(response) { 
			callback(response[0])
		});
}
function onLoginMismatch() {
	var url = window.location.href;
	var domain = extractDomain(url);
	clearFBConnectCookies(appKey, domain);

	onError("Login Mismatch", "It looks like you may have been logged out.  You'll now be taken to the home page where you can log in again.");
}
function extractDomain(url) {
	// we want the stuff between the http:// and the next /
	var start = "http://".length;
	var slashIndex = url.indexOf("/", start+1);
	var domain = url.substring(start, slashIndex);
	var lastDotIndex = domain.lastIndexOf(".");
	var colonIndex = domain.indexOf(":", lastDotIndex);
	if (colonIndex > 0) {
		domain = domain.substring(0, colonIndex);
	}
	var previousDotIndex = domain.substring(0, lastDotIndex-1).lastIndexOf(".");
	domain = domain.substring(previousDotIndex + 1);
	return domain;
}
function alertDialog(title, text, modal) {
	var alertDiv = $("<div></div>");
	alertDiv.attr("title", title);
	alertDiv.append(text);
	if (modal == null || typeof (modal) == 'undefined') {
		modal = true;
	}
	alertDiv.dialog({resizable:false, modal:modal, position:['center', 100], buttons: {"Close" : function() { $(this).dialog("destroy");}}});
}
function getFlexApp(appName) 
{
    if (navigator.appName.indexOf ("Microsoft") !=-1) 
        return window[appName];
    else
        return document[appName];
}

function loadFlash(swfLoc, configLoc, id, replaceId, width, height, installerLoc) {
    var flashvars = {};
    flashvars.tour = "";

    var params = {};
    params.menu = "false";
    params.allowsscriptaccess = "always";
    params.wmode = "transparent";
    
    var attributes = {};
    attributes.id = id;

    if (configLoc != null && configLoc != '') {
    	swfLoc += "?config=" + configLoc;
    }
    swfobject.embedSWF(swfLoc, replaceId, width, height, "9.0.124", installerLoc, flashvars, params, attributes);	
}

function scaleAffinities(affinities, desiredMax, desiredMin) {
	var min = null;
	var max = null;
	desiredMax = desiredMax || 100;
	desiredMin = desiredMin || 10;
	for (var i in affinities) {
		var affinityObj = affinities[i];
		if (min == null || affinityObj.affinity < min) {
			min = affinityObj.affinity;
		}
		if (max == null || affinityObj.affinity > max) {
			max = affinityObj.affinity;
		}
	}
	if (max && max != min) {
		var desiredRange = desiredMax - desiredMin;
		var actualRange = max - min;
		for (var i in affinities) {
			var affinityObj = affinities[i];
			affinityObj.originalAffinity = affinityObj.affinity;
			if (affinityObj.affinity >= 0) {
				affinityObj.affinity = desiredMin + ((affinityObj.affinity - min) / actualRange) * desiredRange;
			}
		}
	}
	return affinities;
}
function convertToCsv(arr) {
	if (arr == null || arr.length == 0) return '';
	
	var csv = '';
	for (var i=0; i<arr.length; i++) {
		if (i > 0) {
			csv += ',';
		}
		csv += arr[i];
	}
	return csv;
}
function sortRandomly(arr) {
	if (arr != null && arr.length > 1) {
		arr.sort(function(a, b) { return Math.round(Math.random())-0.5; });
	}
}

function clearFBConnectCookies(appKey, domain) {
	var loginCookies = ["fbs_" + appKey];
	for (var i=0; i<loginCookies.length; i++) {
		$.cookie(loginCookies[i], null, {domain:domain, path:'/'});
	}
}

function addResponseChoicesToDropDown(dropdown, responseChoices) {
	for (var i=0; i<responseChoices.length; i++) {
		dropdown.append("<option value='" + responseChoices[i].responseId + "'>" + responseChoices[i].text + "</option>");
	}
}
function onError(title, text) {
	var alertDiv = $("<div></div>");
	alertDiv.attr("title", title);
	alertDiv.append(text);
	alertDiv.dialog({resizable:false, modal:true, position:['center', 100], buttons: {"Close" : function() { $(this).dialog("close"); doLogout();}}});
}
function checkForError(result, title, msg) {
	try {
		var status = result.result;
		if (status != "OK") {
			onError(title, msg);
			return true;
		}
	} catch (err) {
		onError(title, msg);
		return true;
	}
	return false;
}

function trackAnalyticsAction(domElement) {
	try {
		var elem = $(domElement);
	    var path = elem.attr("gaId");
	    if (path == null || path == "") {
	        path = elem.attr("id");
	    }
	    if (path == null || path == "") {
	        path = elem.attr("href");
	    }
	    pushAnalyticsPageview(path);
	} catch (err) {}
}

function trackAnalyticsEvent(domElement) {
	try {
		var elem = $(domElement);
	    var category = elem.attr("gac");
	    var event = elem.attr("gae");
	    
	    pushAnalyticsEvent(category, event);
	} catch (err) {}
}
function pushAnalyticsPageview(path) {
	//alert(path);
	_gaq.push(['_trackPageview', path]);
}
function pushAnalyticsEvent(category, event) {
	//alert(category + " " + event);
	_gaq.push(['_trackEvent', category, event]);
}

function newDate(startTime) {
	return Date.parseExact(startTime, "yyyy-MM-dd HH:mm:ss");
}
function makePerformanceTimeText(performance, format) {
	if (typeof(format) == "undefined") {
		format = "h:mm tt";
	}
	var startDate = newDate(performance.start);
	var endDate = startDate.clone().addMinutes(performance.duration);
	return startDate.toString(format) + " - " + endDate.toString(format);
}
function getPerformanceShortName(performance) {
	if (performance.line2 != null && performance.line2 != "") {
		return performance.line2;
	}
	return performance.line1;
}
function getOrdinalDay(entity, festStart, hrShift) {
	var dtObj = Date.parseExact(entity.start, "yyyy-MM-dd HH:mm:ss");
	// subtract x hours so that performances after midnight will be on the prior day
	dtObj.addHours(hrShift);
	var diffMs = dtObj.getTime() - festStart.getTime();
	var diffDays = diffMs / (1000 * 60 * 60 * 24);
	return Math.floor(diffDays);
}
function isPerformanceOnDay(entity, day, hourShift) {
	var dtObj = Date.parseExact(entity.start, "yyyy-MM-dd HH:mm:ss");
	// subtract x hours so that performances after midnight will be on the prior day
	dtObj.addHours(hourShift);
	return dtObj.getDate() == day.getDate();
}

function getStartDateObj(performance) {
	var startObj = performance.startObj;
	if (startObj == null) {
		startObj = newDate(performance.start);
		performance.startObj = startObj;
	}
	return startObj;
}
function comparePerformancesByTime(performanceA, performanceB) {
	var startAObj = getStartDateObj(performanceA);
	var startBObj = getStartDateObj(performanceB);
	var compare = Date.compare(startAObj, startBObj);
	if (compare != 0) {
		return compare;
	}
	compare = comparePerformancesByAlpha(performanceA, performanceB);
	if (compare != 0) {
		return compare;
	}
	// Performances are at the same time.
	// doesn't really matter which one we return,
	// but keep it consistent.
	// Let's use venue ID
	if (performanceA.venueId > performanceB.venueId) return 1;
	if (performanceA.venueId < performanceB.venueId) return -1;
	
	if (performanceA.id > performanceB.id) return 1;
	return -1;
}
function comparePerformancesByAlpha(performanceA, performanceB) {
	if (performanceA.line1 < performanceB.line1) {
		return -1;
	}
	if (performanceA.line1 > performanceB.line1) {
		return 1;
	}
	return 0;
}
function comparePerformancesByAffinity(performanceA, performanceB) {
	return compareByAffinity(performanceA.id, performanceB.id);
}
function compareNumeric(numberA, numberB) {
	if (numberA > numberB) {
		return 1;
	}
	if (numberA < numberB) {
		return -1;
	}
	return 0;
}
function compareByAffinity(performanceIdA, performanceIdB) {
	var affinityObjA = affinities[performanceIdA];
	var affinityObjB = affinities[performanceIdB];
	var affinityA = 50;
	var affinityB = 50;
	if (affinityObjA) {
		affinityA = affinityObjA.affinity;
	}
	if (affinityObjB) {
		affinityB = affinityObjB.affinity;
	}
	var compare = -1 * compareNumeric(affinityA, affinityB);
	if (compare != 0) {
		return compare;
	}
	// same affinity: sort by segment affinity
	compare = -1 * compareNumeric(affinityObjA ? affinityObjA.segmentAffinity : 50, affinityObjB ? affinityObjB.segmentAffinity : 50);
	if (compare != 0) {
		return compare;
	}
	return comparePerformancesByAlpha(entityMap[performanceIdA], entityMap[performanceIdB]);
}
function getNameOrLongName(venue) {
	var name = venue.line3;
	if (name == null || name == '') {
		name = venue.line1;
	}
	return name;
}
function renderPerformances(performances, container, dayTemplate, entryTemplate, attendingCallback) {
	performances.sort(comparePerformancesByTime);
	var prevDate = null;
	var entriesContainer = null;
	for (var i=0; i<performances.length; i++) {
		var performance = performances[i];
		var thisDate = newDate(performance.start);
		// because the start times can run into the next day,
		// and we want to consider those all part of the same "day",
		// the simplest thing to do is subtract 6 hours.
		thisDate.addHours(-6);
		var newDay = false;
		if (prevDate == null) {
			newDay = true;
		} else {
			newDay = prevDate.getDate() != thisDate.getDate();
		}
		prevDate = thisDate;
		if (newDay) {
			var dayContainer = dayTemplate.clone().removeAttr("id");
			$(".dayLabel", dayContainer).text(thisDate.toString("ddd MMM dS"));
			container.append(dayContainer);
			dayContainer.show();
			entriesContainer = $(".entriesContainer", dayContainer);
		}
		var entryDiv = entryTemplate.clone();
		entryDiv.removeAttr("id");
		var venue = venueMap[performance.venueId];
		$(".performerName", entryDiv).text(performance.line1);
		var name = getNameOrLongName(venue);
		$(".venueName", entryDiv).text(name);
		$(".venueSubtitle", entryDiv).text(venue.line2);
		$(".performanceTime", entryDiv).text(makePerformanceTimeText(performance, "h:mm tt"));
		entriesContainer.append(entryDiv);
		if (typeof(attendingCallback) != "undefined" && attendingCallback != null) {
			var attending = attendingCallback(performance.id);
			if (attending) {
				entryDiv.addClass("in");
			} else {
				entryDiv.addClass("out");
			}
		}
		entryDiv.data("performance", performance);
		entryDiv.show();
	}
}
function extractEntityId(div) {
	div = $(div);
	if (div.length == 0) {
		return null;
	}
	var cssClass = div.attr("class");
	var prefix = "performer-";
	var start = cssClass.indexOf(prefix);
	var end = cssClass.indexOf(" ", start);
	if (end < start) {
		end = cssClass.length;
	}
	var id = cssClass.substring(start + prefix.length, end) * 1;
	return id;
}
function updateInOutStatus(entityId, isIn, updateCount) {
	var tile = $(".performer-" + entityId);
	var classes = {remove:"out", add:"in"};
	var incr = 1;
	if (!isIn) {
		classes.remove = "in";
		classes.add="out";
		incr = -1;
	}
	
	tile.removeClass(classes.remove).addClass(classes.add);	
	if (updateCount) {
		var count = lineupCounts[entityId];
		if (!count) {
			count = 0;
		}
		count += incr;
		tile.find(".countNum").text(numberWithCommas(count));
		tile.find(".countNoun").text("fan" + (count != 1 ? "s" : ""));
		lineupCounts[entityId] = count;
	}
}
function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(?:\d{3})+(?!\d))/g, ",");
}


