/* $Rev: 3211 $ */

// pass name, name_popup and name_link are assumed as id's.
function helpbox(name, options)
{
	if ( ! options) options = {};

	var popname = '#' + name + '_bubble';
	var linkname = '#' + name + '_link';
	
	jQuery(linkname).wrapInner('<a href="#" class="help"></a>');
	var popup = jQuery(popname);
	popup.addClass('help_bubble').pchDialog(linkname, { position: 'anchor', anchor: 'tr', timeout: 15000, width: options.width || 300 });
}

jQuery.fn.pchDialog = function(uiTrigger, options)
{
	var popup = this;
	options.trigger = uiTrigger;
	
	var tEvent = options.tEvent || 'click';
	
	uiTrigger = jQuery(uiTrigger);
	uiTrigger
	.addClass('uiTrigger')
	.bind(tEvent, function(event)
	{
		//event.preventDefault();
		//event.stopPropagation();
		
		// close all other popups
		var allPopups = jQuery('div.ui-dialog:visible');
		if (allPopups.length > 0) allPopups.hide();
		
		// show current
		popup.show();
		popup.dialog(options);
		
		if (options.timeout) 
			setTimeout("jQuery('#" + popup.id + "').fadeOut('normal').dialogClose();", options.timeout);
		
		//if for some reason the popup doesn't work, allow link to pass
		if (jQuery('div.ui-dialog:visible').length > 0) 
			return false;
		else return true;
	});
	
	return this;
};
	
// if i run this every pchDialog call, there gets to be quite a few
jQuery(document).mouseup(function(event){
	var allPopups = jQuery('div.ui-dialog:visible');
	if (allPopups.length < 1) return;
	
	var ele = jQuery(event.target);
	
	var notDialog = (!ele.parents().is('div.ui-dialog') && !ele.is('div.overlay'));
	var notTrigger = (!ele.parents().is('uiTrigger') && !ele.is('uiTrigger'));
	var notCalendar = (!ele.parents().is('#calendar_div'));
	
	if (allPopups.length > 0 && notDialog && notTrigger && notCalendar) 
	{
		allPopups.fadeOut('normal').dialogClose();
		return false;
	}
});

/** 
	like jQuery.post() but with a few methods for inserting returned content
 */
jQuery.pchPost = function(action, values)
{
	values += '&ajax=true';
	
	jQuery.post(
		action
	,	values
	,	function(data)
		{
			//returned info should either be 'failed' or <div.message><div.content>
			if (data != 'failed')
			{
				//won't be recognized as traversable html otherwise
				var retval = jQuery('<div id="container">' + data + '</div>');
				
				var message = jQuery('div.message', retval).html();
				
				//content needs to be set up so jquery understands it(e.g. if it's a tr, needs to be wrapped in a <table><tbody></tbody></table>
				var content = jQuery('.content', retval).children();
				
				// message always contained in div#message
				if (message)
				{
					jQuery('#message').html(jQuery(message)); // should there be a timeout which clears the message div?
					
					setTimeout("jQuery('#message').slideUp().html('').show();", 30000);
				}
				
				if (content.length > 0)
				{
					content.each(
						function()
						{
							var $this = jQuery(this);
							var thisid = $this.attr('id');
							var thiscontent = $this.html();
							
							jQuery('#' + thisid).html(thiscontent);
						});
				}
				
				dsrInit();
			}
		}
	,	"html"
	);
}

/**
	takes input objects, and jumps through them as though they were 1 input
 */
jQuery.pchInputLink = function(inputList)
{
	var max = inputList.length - 1;
	
	jQuery.each(
		inputList
	, 	function(i, v)
		{
			var input = inputList[i];
			var prev = (i > 0) ? inputList[i-1] : false;
			var next = (i < max) ? inputList[i+1] : false;
			
			input.keyup(
				function(e)
				{
					var $this = jQuery(this);
					var keyCode = e.keyCode;
					
					// only jump through boxes if keyCode in whitelist
					// 0-9(48-57), numpad 0-9(96-105), aA-zZ(65-90), bkspc(8)
					if ((keyCode > 57 && keyCode < 65) || (keyCode > 90 && keyCode < 96) || keyCode > 105 || (keyCode < 48 && keyCode != 8))
						return;
						
					//37 = left arrow, 39 = right, incorporate these at some point
					
					if ($this.val().length == $this.attr('maxlength') && next !== false) // forward to next box
					{
						if (next.val().length > 0)
							next.focus().select();
						else next.focus();
					}
					else if ((keyCode == '8' || keyCode == '46') && $this.val().length < 1 && prev !== false) // go to prev box
					{
						if (prev.val().length > 0)
							prev.focus().val(prev.val());
						else prev.focus();
					}
				});
		}
	);
}

/**
 * used on date object, will return given date as a string in a particular format MM/dd/yy
 */
jQuery.pchDate = function(d)
{
	var month = (d.getMonth() + 1).toString();
	if( month.length == 1 ) 
		month = '0' + month;
	
	var day = d.getDate().toString();
	if( day.length == 1 ) 
		day = '0' + day;
		
	var year = d.getYear().toString().substring(1);
	
	var dateString = month + '/' + day + '/' + year;
	
	return dateString;
}

jQuery.fn.defaultText = function(defText)
{
	var input = this;
	if (input.val().length > 0) return this;
	var maxLen = parseInt(input.attr('maxlength'));
	if (isNaN(maxLen) || maxLen < 1) maxLen = 40;
	
	input
	.attr('maxlength', defText.length)
	.val(defText)
	.focus(
		function()
		{
			if (input.val() == defText)
				input.attr('maxlength', maxLen).val('');
		}
	).blur(
		function()
		{
			if (input.val() == '') 
				input.attr('maxlength', defText.length).val(defText);
		}
	);
	
	// avoid sending default text on submit, might cause errors
	jQuery('input[type=submit]').mousedown(
		function()
		{
			if (input.val() == defText) input.val('');
		});
	
	return this;
};

/**
	Disables submit button(s) 
	
	condition 	string 	button disabled if eval'd to true
	o			object	options
						watchTrigger (DOM elements that will trigger condition check)
						triggerEvent (array of events that will trigger condition check, default is 'change')
						noticeText	 (explanation for disabled button, accepts html)
						spanclass	 (class added to wrapping span, popup event fires onclick of this)
	oPrompt		object	popup options
						see jquery.impromptu.js
 */
jQuery.fn.disableButton = function(condition, o, oPrompt)
{
	var trigger = o.watchTrigger || false;
	var triggerEvent = o.triggerEvent || ['change'];
	if (typeof triggerEvent != "object") triggerEvent = [triggerEvent];
	var noticeText = o.noticeText || false;
	var spanClass = o.spanclass || 'disabled_button';
	var safari = jQuery.browser.safari;
	var callback = jQuery.isFunction(o.callback);
	
	var promptDef = {
		overlayspeed: 0.01
	,	promptspeed: 0.01
	,	show: 'fadeIn'
	};
	
	var oPrompt = jQuery.extend({}, promptDef, oPrompt);
	
	var button = this;
	
	button.mousedown(
		function(event)
		{
			//console.log(condition + ': "' + eval(condition) + '"');
			if (eval(condition))
			{
				event.preventDefault();
				
				if (noticeText.length > 0)
					jQuery.prompt(noticeText, oPrompt);
					
				return false
			}
			else return true;
		}
	).click(function(){ if (eval(condition)) return false; });
		
	
	//check condition, and assign to trigger
	if (eval(condition))
	{
		button.addClass('disabled_button');
		if (safari) button.attr('disabled', true);
	}
	//console.log(condition + ': "' + eval(condition) + '"');
	
	if (trigger)
	{
		jQuery.each(triggerEvent, 
			function(i, tEvent)
			{
				jQuery(trigger).bind(tEvent, 
					function()
					{
						//console.log(condition + ': "' + eval(condition) + '"');
						if (eval(condition))
						{
							button.addClass('disabled_button');
							if (safari) button.attr('disabled', true);
						} else {
							if (safari) button.attr('disabled', false);
							button.removeClass('disabled_button');
						}
					});
			});
	}	
}


jQuery.fn.hoverIntent = function(f,g) {
	// default configuration options
	var cfg = {
		sensitivity: 7,
		interval: 100,
		timeout: 0
	};
	// override configuration options with user supplied object
	cfg = jQuery.extend(cfg, g ? { over: f, out: g } : f );

	// instantiate variables
	// cX, cY = current X and Y position of mouse, updated by mousemove event
	// pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
	var cX, cY, pX, pY;

	// A private function for getting mouse position
	var track = function(ev) {
		cX = ev.pageX;
		cY = ev.pageY;
	};

	// A private function for comparing current and previous mouse position
	var compare = function(ev,ob) {
		ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
		// compare mouse positions to see if they've crossed the threshold
		if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
			jQuery(ob).unbind("mousemove",track);
			// set hoverIntent state to true (so mouseOut can be called)
			ob.hoverIntent_s = 1;
			return cfg.over.apply(ob,[ev]);
		} else {
			// set previous coordinates for next time
			pX = cX; pY = cY;
			// use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
			ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
		}
	};

	// A private function for delaying the mouseOut function
	var delay = function(ev,ob) {
		ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
		ob.hoverIntent_s = 0;
		return cfg.out.apply(ob,[ev]);
	};

	// A private function for handling mouse 'hovering'
	var handleHover = function(e) {
		// next three lines copied from jQuery.hover, ignore children onMouseOver/onMouseOut
		var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
		while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }
		if ( p == this ) { return false; }

		// copy objects to be passed into t (required for event object to be passed in IE)
		var ev = jQuery.extend({},e);
		var ob = this;

		// cancel hoverIntent timer if it exists
		if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }

		// else e.type == "onmouseover"
		if (e.type == "mouseover") {
			// set "previous" X and Y position based on initial entry point
			pX = ev.pageX; pY = ev.pageY;
			// update "current" X and Y position based on mousemove
			jQuery(ob).bind("mousemove",track);
			// start polling interval (self-calling timeout) to compare mouse coordinates over time
			if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}

		// else e.type == "onmouseout"
		} else {
			// unbind expensive mousemove event
			jQuery(ob).unbind("mousemove",track);
			// if hoverIntent state is true, then call the mouseOut function after the specified delay
			if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
		}
	};

	// bind the function to the two event listeners
	return this.mouseover(handleHover).mouseout(handleHover);
};

jQuery.fn.confirm = function(msg)
{
	if ( ! msg || msg == '')
		msg = 'Are you sure?';
	
	var $this = jQuery(this);
	$this.mousedown(
		function(e)
		{
			e.preventDefault();
			e.stopPropagation();
			
			// add selected flag so callback can trigger it
			$this.addClass('click_flag');
			
			var options = {
				buttons: {
					Cancel: false
				,	Ok: true
				}
			, 	overlayspeed:'fast'
			,	submit: finishClick
			, 	promptspeed:'fast'
			, 	show:'fadeIn'
			};
			
			jQuery.prompt(msg, options);
		}
	);
}

function finishClick(v,m)
{
	var clicked = jQuery('.click_flag');
	
	if (v)
		clicked.click();
	else clicked.removeClass('click_flag');
	
	return true;
}

jQuery.fn.hoverClass = function(c, onIntent) {
	var action = onIntent === true ? 'hoverIntent' : 'hover';

    return this.each(function(){
        jQuery(this)[action]( 
            function() { jQuery(this).addClass(c);},
            function() { jQuery(this).removeClass(c); }
        );
    });
}; 

// allow thumbnails to update one main image
// main - pass main beauty shot object
// thumbs - pass thumbs object, usually links wrapping thumbs
// attr_map - define attributes to copy from thumb to beauty, {main attr: thumb attr, main attr2: thumb attr2 ... }
// options - event to trigger swap, etc.
// TODO: add animation for different widths as well as height
jQuery.fn.beautySwap = function(thumbs, attr_map, o)
{
	var main = this;

	// if no map passed, thumb href becomes beauty src
	attr_map_defaults = {
		"src": "href"
	,	"alt": "alt"
	}
	
	options_defaults = {
		swapEvent: 'click'
	,	callback: function(){}
	}
	
	attributes = attr_map || attr_map_defaults;
	var options = jQuery.extend({}, options_defaults, o);
	
	// if no main image or no thumbs, no reason to go on
	if (thumbs.length == 0)
		return false;
		
	var main_parent = main.parent();
	var main_parent_height = main.height();
	main_parent.attr('size_fix', 0);
		
	thumbs.bind(options.swapEvent, 
		function(e)
		{
			e.preventDefault();
			e.stopPropagation();
			
			var $thumb = jQuery(this);
			
			main_parent.addClass('loading');
			
			if ( main_parent.attr('size_fix') == 0)
			{
				main_parent.height(main_parent_height);
				main_parent.attr('size_fix', 1);
			}
			
			main.fadeTo
			(
				'fast' 
			,	0.01
			,	function()
				{
					var same_image = true;
					jQuery.each
						(
							attributes
						,	function(main_attr, thumb_attr)
							{
								if (main.attr(main_attr) != $thumb.attr(thumb_attr) && same_image  === true)
									same_image = false;
								
								main.attr(main_attr, $thumb.attr(thumb_attr));
							}
						);
					
					// if all attrs match up, just fade back in
					if (same_image === true)
					{
						main.fadeTo(500, 1.0);
						return false;
					}
						
					var newImg = new Image();
					
					jQuery(newImg)
					.load(function(){
						var $this = jQuery(this);
						
						// have to insert image into dom to get height
						jQuery('body').append($this.hide());
						var newHeight = $this.height();
						$this.remove();
							
						if (newHeight != main_parent.height())
						{
							main_parent.animate
							(
								{ height: newHeight }
							, 	400 
							,	null
							,	function()
								{ 
									main.fadeTo(500, 1.0); 
									main_parent.removeClass('loading');
								}
							);
						}
						else
						{
							main.fadeTo(500, 1.0); 
							main_parent.removeClass('loading');
						}
						
					}).attr('src', $thumb.attr(attributes['src']));
				}
			);
			
			options.callback($thumb);
		
			return false;
		});
}

jQuery.doMoveScreen = function(element)
{
	var wnd = jQuery(window);
	var offset = element.offset();
	var yPage = window.pageYOffset;
	var xPage = window.pageXOffset;
	var y = yPage;
	var x = xPage;
	
	//if popup bottom is below or popup top is above
	if ((offset.top + element.height()) > (wnd.height() +  yPage) || offset.top < yPage)
		y = offset.top - wnd.height()/2;
		
	//if popup right is to right of popup left is to left	
	if ((offset.left + element.width()) > (wnd.width() + xPage) || offset.left < xPage)
		x = offset.left;
			
	if (y != yPage || x != xPage)
		window.scrollTo(x, y);
}

/*
 * inspired by Alen Grakalic (http://cssglobe.com)
 */
 
jQuery.fn.imagePreview = function(o){
		
	var default_opt = {
		xOffset: 10
	,	yOffset: 30
	,	anchor: false
	,	disableLink: true
	,	attr: 'href'
	,	width: 250
	}
	
	var options = jQuery.extend({}, default_opt, o);
	var $this = this;
	
	// $("a.preview") // example target, a.preview with thumbnail inside
	$this.hoverIntent(
		function(e)
		{
			var anchor = jQuery(this);
			
			var title = anchor.attr('title');
			anchor.attr('t', title);
			anchor.attr('title', ''); // unset this on hover so it doesn't look shitty
			
			// popup caption (can I make this take html?)
			var c = (title != "") ? '<div class="caption">' + title + '</div>': "";
			var preview = jQuery("<div id='preview'><img src='"+ anchor.attr(options.attr) +"' alt='Image preview' />"+ c +"</div>");
			
			preview.add(jQuery('img', preview)).width(options.width);
			
			jQuery("body").append(preview);
			
			if (options.anchor === false)
			{
				var top = (e.pageY - parseInt(options.yOffset));
				var left = (e.pageX + parseInt(options.xOffset));
			}
			else
			{
				// determine whether to display popup on left or right
				// get body width, if left > body.width()/2
			
				var top = (parseInt(anchor.offset().top) - parseInt(options.yOffset));
				var left = (parseInt(anchor.offset().left));
				
				var previewWidth = parseInt(jQuery('img', preview).css('width')) + 2;
				var anchorWidth = anchor.outerWidth();
				
				if (left > jQuery('body').width()/2)
				{
					// adjust so right edge of image matches opposite xOffset from left side of anchor
					left = left - previewWidth - parseInt(options.xOffset);
				}
				else
				{
					// adjust to left edge of image matches xOffset from right side of anchor
					left = left + anchorWidth + parseInt(options.xOffset);
				}
			}
			
			preview.css({"top": top + "px", "left": left + "px"}).fadeIn("normal");
	    },
		function()
		{
			var anchor = jQuery(this);
			
			var title = anchor.attr('t');
			anchor.attr('title', title);
			
			jQuery("#preview").remove();
	    });	
    
    if (options.anchor === false)
    {
		$this.mousemove(
			function(e)
			{
				var preview = jQuery("#preview");
				
				// TODO: add bounding so preview won't go offscreen
				var top = (e.pageY - parseInt(options.yOffset));
				var left = (e.pageX + parseInt(options.xOffset));
				
				preview.css({"top": top + "px", "left": left + "px"});
			});
	}
	
	// we don't want this link to open up image
	if (options.disableLink === true || options.attr == 'href')
	{
		$this.click(
			function(e) 
			{
				e.preventDefault();
				e.stopPropagation();
				
				return false;
			});	
	}
};