function openModal(url, data, modalArgs)
{
	trackModalAnalytics(url);

	if (data == null)
		data = {};

	if (typeof(data) == "object")
	{
		data["_s"] = randStr(10);
		data = objectToString(data);
	}
	REST(url, data, function(data){ modalBox(data, modalArgs); }, { type: "get", dataType: "html" })
}

function closeModal(modalArgs){ return modalBox(null, modalArgs) }

function errorModal(title, error) { openModal("/overlay/message", {title: title, message: error}); }

function isModalOpen() { return $("#nimble_modal").length > 0; }

/**
 * Opens up a modal window with provided content
 * modalArgs can define the following optional params:
 *
 * openCallback: function
 * closeCallback: function
 * overlayOnclick: function
 * noScroll: bool -- if true, modal window won't scroll when page is scrolled (useful for modals that may be too tall...)

 **/
function modalBox(content, modalArgs) {
	var modalArgs = modalArgs || {};
	var createModal = $("#nimble_overlay").length == 0;

	var width = String(modalArgs.width || 350).replace(/\D/g, "");
	var openCallback = modalArgs.openCallback;
	var closeCallback = modalArgs.closeCallback;
	var overlayOnclick = modalArgs.overlayOnclick || function(){ modalBox(); }
	var pin = modalArgs.pin !== false; // default to pinning the modal

	if (!content && globals.restoreContent)
	{
		restoreModalState();
		return;
	}

	if(!content) {
		$('#nimble_modal').remove();
		$('#nimble_overlay').fadeOut(function(){$(this).remove(); if (typeof(closeCallback) == "function"){closeCallback();} });
		//try{if(IE6){$('body').find('select.unhideThis').removeClass('unhideThis').visibility('visible');}}catch(err){};
		//$('embed.unhideThis, object.unhideThis').removeClass('unhideThis').css('visibility', 'visible');

		return false;
	}

	if (createModal) {
		//try{if(IE6){$('body').find('select:visible').addClass('unhideThis').visibility('hidden');}}catch(err){};
		//$('embed:visible, object:visible').addClass('unhideThis').css('visibility', 'hidden');
		$('body').append('<div id="nimble_overlay"></div>');
		$('#nimble_overlay').css({
			height : $(document).height()
		}).fadeTo(500, 0.75).click(overlayOnclick);
		$('body').append('<div id="nimble_modal"></div>');
		$('#nimble_modal').css({
			width : width + "px",
			top : $(document).scrollTop() + 50,
			marginLeft : -(Math.ceil((width)/2))
		}).append(content);
	}
	else // A modal is already open, reset its bound functions
	{
		$(document).unbind('scroll');
		$('#nimble_overlay').unbind("click").click(overlayOnclick);
		$("#nimble_modal").html(content);
	}

	width = String(modalArgs.width || $("#nimble_modal :first").width()).replace(/\D/g, "");
	$('#nimble_modal').css({width: width, marginLeft: -(Math.ceil(width / 2))});
	$('#nimble_modal input:eq(0)').focus();
	//$('#nimble_modal a:eq(0), #nimble_modal input, #nimble_modal textarea').focus();

	if (typeof(openCallback) == "function")
		openCallback();

	if (pin)
	{
		$(document).unbind('scroll');

		scrollTo(0, 0);
		$('#nimble_modal').animate({
			top: 50
		}, 0);
	}
	else
	{
		$(document).bind('scroll', function(){
			$('#nimble_modal').queue([]); // scroll fires many times on a scroll, we don't want the animation queue to back up, clear it.
			$('#nimble_modal').animate({
				top: $(document).scrollTop() + 50
			}, 300);
		});
	}
};

function saveModalState(saveFormState)
{
	saveFormState = (saveFormState === true);

	var isFromOverlay = isModalOpen();
	if (!isFromOverlay)
		return;

	globals.restoreContent = $("#nimble_modal").html();

	if (saveFormState)
	{
		globals.restoreForm = {};
		var tmpInputs = $("#nimble_modal input, "+ MODAL_ID +" select");

		for (var i = 0; i < tmpInputs.length; i ++)
		{
			var curInput = tmpInputs[i];

			if (curInput.type == "checkbox")
				globals.restoreForm[curInput.id] = curInput.checked;
			else
				globals.restoreForm[curInput.id] = curInput.value;
		}
	}
	else
		globals.restoreForm = {};
}

function restoreModalState()
{
	if (globals.restoreContent)
		modalBox(globals.restoreContent)
	else // No modal to restore. Close the overlay (there might be a form underneath that instigated the overlay)
		closeModal();

	if (globals.restoreForm)
	{
		for (var key in globals.restoreForm)
		{
			try {
				if (/password/i.test(key)) // don't restore password fields
					continue;

				if (key == "credit_package")
					$("#nimble_modal #credit_"+ globals.restoreForm[key]).trigger("click");
				else
				{
					var curInput = $("#nimble_modal #"+ key)[0];

					if (curInput.type == "checkbox")
						curInput.checked = globals.restoreForm[key];
					else
						curInput.value = globals.restoreForm[key];
				}
			} catch(e) {}
		}
	}

	globals.restoreContent = null;
}

function processStaticOverlays(strOverlaySelector)
{
	$(strOverlaySelector).click(function(){
		var src = String(this.href).replace(/^.*static_overlay/, "/static_overlay");
		lastStaticPageRequest = this.text || this.href;
		
		openStaticOverlay(src);

		return false;
	});
}

function openStaticOverlay(src)
{
	trackModalAnalytics(src);

	REST(src, {_s: randStr(10)}, function(data){
		modalBox(data, {pin: true, width: 798, openCallback: function(){ processStaticOverlays("#nimble_modal .static-overlay"); }});
	}, {type: "GET", dataType: "html", error: function(){ alert("Page missing: "+ src); }});
}

function trackModalAnalytics(url)
{
	url = url || "";
	// For now, we're not interested in the generic notices (these mostly include error messages and the like -- nothing too important happens in them currently)
	if (!url || /generic_notice/.test(url))
		return;

	if (globals.isGAEnabled)
	{
		try {
			_gaq.push(['_trackPageview', url]);
		} catch(e) {}
	}
}

