/*
	
	Ecotrust FoodHub Global Javascript Functions
	By Will Moore - ISITE Design
	
*/

//start the jQuery functions
$(document).ready(function() {

	$('html').addClass("js-on");

	// Browser sniff. Adds class names. creates global var 'snuff' with browser name.
	$("html").sniff();
	
	//and encourage
	if (snuff == "ie ie6" || snuff == "ff ff2" || snuff == "sf sf2") {
		$('#header').before("<div id='get-a-new-browser'>Looks like you're using an older browser. That's no problem but if you have the option, consider <a href='http://download.cnet.com/windows/browsers/' title='Upgrade to the newest version of Firefox, Opera, Chrome, Safari or Internet Explorer'>upgrading to something shiny and new</a>.</div>");
	};
	

	// Fix IE6 :hover
	if(snuff == "ie ie6"){
	    $("#nav li, button, ul.actions li").hover(
			function() { $(this).addClass("ieover"); },
			function() { $(this).removeClass("ieover"); }
	    );
	}// IE Hovers

	// we're hijacking cakePHPs autoinserted inline confirm() function but need those links to return false
	$("a[onclick*='confirm']").live("click", function(){		
		return false;	
	});	


	// show a tooltip for all links and form elements with a title attribute
	/* seems to really slow things down.
	$('a[title], form *[title]').live("mouseover", function(){
		$(this).tooltip({
			delay: 0,
			showURL: false
		});
	});
	*/
	
	// fadetoyellow for cake's default screen messages
	// only for 'success messages'
	//$('#message-wrap.success').fadeIn(1000).fadeTo(15000, 1).fadeTo(12000, .7).fadeOut(3000); 
	
	// make sure folks notice the system messages
	$('#message-wrap')
		.animate({paddingTop:"9px"}, 100)
		.animate({paddingTop:"7px"}, 100);
	
	// let's make tabs.
	$('.tabs').idTabs();
	
	// grab the label, put it in the input
	$('#header form input, #product-name').inputSetter(1);

	//character limits. actual limit is part of the label text.
	$(".charactersremaining").charactersRemaining();
	$('.charactersremaining em').text("remaining");
	

	// make certain tables sortable via js. most tables are sorted via cake's server side sorting to support pagination
	$('.harvest-plan').tablesorter();


	// let's do some autocomplete
	
		// product search has a display field and an ID field that's populated on success.
		
		$('#product-name').focus(function () {
			$('#product-id-searched').val("");
		});

		// we need the ID from the add-product autocomplete form to send to the server.
		$("#product-name").result(function(event, data, formatted) {
			if (data){
				$("#product-id-searched").val(data[1]);
			}	
		}).blur(function(){
		    $(this).search(); //force a search afterwards 
		});

		$('#product-name').autocomplete("/products/autocomplete", {
			cacheLength: 1,
			matchContains: false,
			minChars: 1,
			max: 500,
			//autoFill: true, //creates false positives
			delay: 0,
			//mustMatch: true,
			scrollHeight: 200
		});
	
		$('#header form input, #search-terms input').autocomplete("/search/autocomplete", {
			matchContains: true,
			minChars: 1,
			max: 500,
			// mustMatch: true, // causes not found text to be removed from the box. was confusing users.
			scrollHeight: 300
		});
	
		// Shouldn't need to do this often, but if autocomplete results are not as expected uncomment the following temporarily
		// $('#header form input, #search-terms input, #product-name').flushCache();


		
	
	// faq expand/collapse
	enableExpand("dl.faq");


	
	
	/*
	 * Links with class="disabled" should not do anything except perhaps scroll to the top of the screen
	 */
	$('body').click(function (event) {
		var $target = $(event.target);
		if ($target.is('.disabled') || $target.is('.disabled span')) {
			document.location.href="#";
			return false;
		}
	});

	
	/*
		My Products/Add Products	
	*/
	
	// add product dropdown
	$('.add-product-type').hide();
	$('.add-product-button-wrap').hover(function(){
			$('.add-product-type').slideDown('fast');
		}, function(){
			$('.add-product-type').hide();
		}	
	);
	
	
	// add/edit product page
		$('select#attributes-copy').bind("change", copyProductAttributes);
		
		$('.product-list .delete').live("click", function(){
			if ($('body').is('.auto-login')) 
			{
				document.location.href="#";
				return false;
			}
			var productID = $(this).parents("ul").parent("li").attr("id");
			var productName = $(this).parents("ul").prev("a").text();
			var url = $(this).attr("href");

			// if yes, go to url
			confirmIt("Are you sure you want to delete "+ productName +" from your product list?", url);
				
			return false;
		});		
		

	// what's fresh interactions
	$('#select-fresh').hide();

	$('.update-fresh').bind("click", showFresh);
	
	$('#select-fresh').bind("submit", updateFresh);
	
	$('#select-fresh a.cancel').bind("click", function(){showFresh("hide");});
	

			
	// Login Action
	$('#form-login').bind("submit", fhCheckLogin);
	
	$('#btn_register span').bind("click", registerUser);
	
	$('.forgot-password').bind("click", forgotPassword);
	


	
	//Registration stuff
	if($('.registration-form form').length){
		$('#LocationZip').mask("99999");
		$('.input-phone').mask("(999) 999-9999");
		$('#tos-wrap').hide();
		$('.tos-link').click(function(){
			$('#tos-wrap').slideToggle();
			return false;	
		});

		//some basic validation
		$('.registration-form form').bind('submit', checkRegistration);
		$('.register-page #LocationStateId').bind('change', setCounties);
		$('.register-page #LocationCounty').find("optgroup[label=Oregon] option:first").attr("selected", "selected"); //set the county to default to oregon on the register page
	
	}
	
	
	
	/*
		profile edit form
	*/
		
	if($('body').is('.profile-edit-page')){
		
		// toggling farmers markets and distrubutors
		//
		// the intitial show/hide - TOP Level fieldsets (Stage/Region)
		if($('select.associations-selector').length){
			$('select.associations-selector').each(
			function(){
				if($(this).val() != "1"){
					$(this).parents('fieldset.associations').find('fieldset').hide();	
				}
			});
		}	

		//listen for changes to the select and show/hide TOP Level fieldsets (Stage/Region)
		$('select.associations-selector').change(function(){
			if($(this).val() == "1"){
				$(this).parents('fieldset.associations').find('fieldset').show();
			} else{
				$(this).parents('fieldset.associations').find('fieldset').hide();
			}
		});

		// accordian style for the inner region fieldsets 
		//
		// on page load, add .open to any fieldset with ticked checkboxes. this should prolly be done with php.
		$('fieldset.associations fieldset fieldset').each(function() {
			$(this).find("input:checked:first").parents('fieldset').addClass("open");
			$(this).not('.open').find('div.inner-wrap').hide();
		});
		
	
		
		// do some toggling for associations.
		$('fieldset.associations fieldset fieldset legend').toggle(
			function(){
				$(this).parent("fieldset").addClass("open").end().next(".inner-wrap").show();	
			},
			function(){
				$(this).parent("fieldset").removeClass("open").end().next(".inner-wrap").hide();	
			}
		);
				

		$('.input-phone').mask("(999) 999-9999");

		// make the jump links scroll
		$('.profile-edit-page #secondary ul a').bind("click", function(){
			var linkTarget = $(this).attr("href");
			IX_scrollPage(linkTarget, "slow");
		});
	
		
		//save and continue	
		var $theSaveButton = $('.edit-profile button');
		$('.edit-profile>fieldset>fieldset').after($theSaveButton);
			//last one isn't a continue.
		$('.edit-profile button').not('.edit-profile button:last').addClass("button-continue").find("span").text("Save and continue editing");
		
		$('.button-continue').live("click", function(){
			$('#profile-continue').val("true");
			
			var theSection = $(this).next("fieldset").attr("id");
			
			$('#profile-current-section').val(theSection);			
		});
		
		// need to set a delay on the scroll to #hash link when it's passed in externally 
		// because of all the JS hiding on the page, positioning gets confused if we let the browser do it automatically.
			//if there is a flash message as an error, let's go there instead
		if(self.document.location.hash){
			setTimeout("IX_scrollPage(self.document.location.hash, 'slow')",1250);
		}
		
	} //profile-edit-page
	
		/*
		//togglers on dashboard. needs cookies to be worthwhile. kept for v2.
		if($('body').is('.dashboard-page')){
			$('.widget h2').prepend("<span class='toggler'></span>");
			
			$('.widget h2 span').click(function(e){
				toggleWidgets(e);	
			});
			
			
		} //dashboard-page
		*/
	
	
	// profile page sidebar links. Forces breaks in the links so sidebar doesn't break.
	$("#user-data dl dd a").bnsp();
	
	
	
	if($('.requests-page #my-requests').length){
		$('.tabs li a').click(function(){
			return true;	
		});
	}
	
	
	
	//hide stuff with the escape key. need to ensure there's not a message happening before we hide that window.
	

	$(document).keyup(function(event){
	    if (event.keyCode == 27) { //esc
			
			if($('.confirm').length){
				$('.confirm').remove();
				$('.jqmOverlay').remove();
			}
			
			if($('.main #contact-list .contact-list')){
				$('.contact-list').remove();
			}
			
	
	    }
	});	

	
	
	
	
	
		
});// document ready / end jquery functions



/*
	FoodHub JS Functions
*/


// set some constants
function FHGlobalBits () {
	this.loader = '<h2 class="loader">Loading...</h2>';
	this.test = 'test';
	this.Products = fhProducts;
	this.Messages = fhMessages;
	this.Results   = fhResults;
	this.fevent = '';
	this.ftarget = '';	
	}


var FH = new FHGlobalBits;


function fhProducts(event, target){
	cl("fhProducts");	
	
	var $target = $(event.target);
	
	if($target.is("h1")){
		cl("h1!");
		//console.debug(FH.hello)
	}
	//FH.Products(event);
	
}

function fhMessages(event, target){
	cl("fhMessages");
		
}
function fhResults(event, target){
	cl("fhResults");
		
}




// login functions
function fhCheckLogin(){
	var failed = false;
	
	$("#form-login input").each(function()
	{
		if($(this).val() == "")
		{
			failed = true;
			$(this).parents("li").addClass("error");
		}
		
	});
	
	if(failed) 
	{
		$('#form-login').find("h4").remove().end()
			.prepend('<h4 class="error">Please make sure both fields are filled in correctly.</h4>');
		return false;
	}							
	
	return true;
}


//login box registration
function registerUser(){

	//var inputs = $('#form-login').serialize();
	$('#form-login').unbind("submit", fhCheckLogin);
	$('#form-login').attr("action", "/users/register");
	$('#form-login').submit();
	
	return false;

}


//login box password reminder
function forgotPassword() {
	if($('#email').val() != "")
		//if they've entered an email address, use it to test for an account
	{
		var email = $('#email').val();
		var inputs = $('#form-login').serialize();
		$.ajax({
			type: "POST",
			url: "/users/reset_password",
			data: inputs,
			success: function(msg){
				if(msg == "0"){
					$('#secondary .widget h4').remove(); //get rid of any existing error messages.
					$('#secondary .widget label[for=email]').before('<h4 class="error">We could not find the email address you entered. Please check it and try again, or click the join button to sign up.</h4>');
				}
				if(msg == "1"){
					$('#secondary .widget').html('<h3>Please check your email. Password reset instructions have been sent to <em>' + email + '</em>.');	
				}
			},
			error: function(msg){
				alert(msg);
			}	
		});
							
	}
	else
	{
		//if the email address is blank, let's show a lightbox and ask for it. 	
		jQuery('body').append('<div class="confirm"><form><label class="confirm-message">Please enter your email address</label><input type="text" id="forgot-email" name="data[User][email]" /><a href="#" class="yes">Submit</a></form><a href="#" class="confirm-cancel jqmClose">Cancel</a></div>');
		jQuery(".confirm").jqm({modal:true, overlay: 88});
		jQuery('.confirm').jqmShow().find('a').click(function(){
	        if(this.className == 'yes'){	
				var theEmailSerialized = $('.confirm form').serialize();
				var theEmail = $('#forgot-email').val();
				
				$.ajax({
				  type: "POST",
				  url: "/users/reset_password",
				  data: theEmailSerialized,
				  success: function(msg){
					if(msg == "0"){
						$('#secondary .widget label').prev("h3").remove();
						$('#secondary .widget label[for=email]').before('<h3 style="padding: 0">We could not find your account. Please check your email address or register with Foodhub.</h3>');
						$('#secondary #email').val(theEmail);
					}
					if(msg == "1"){
						$('#secondary .widget').html('<h3>Please check your email. Password reset instructions have been sent to <em>' + theEmail + '</em>.');	

					}
				  },
				  error: function(msg){
					alert(msg);
				}	
				});
			}	
	        $('.confirm').jqmHide().remove();
	      });

	}
	return false;
}


//so we can confirm stuff first. this is called from confirmIt, generally.
function ajaxIt(url){
	// curently being used on delete product but only if specifically called - atm it's being skipped.
	
	var prodID = $('a[href='+url+']').parents(".actions").parent("li");
	
	$.ajax({
	  type: "POST",
	  url: url,
	  success: function(msg){
		$(prodID).hide("slow");
	  },
	  error: function(msg){
		alert(msg);
	}	
	});	
	
	//$(prodID).hide("slow")
	return true;	
	
	
}

//manage product functions

//update fresh sheet
function showFresh(hideIt){
	if(hideIt == "hide"){
		$('#primary div, #primary ul.tabs').show();
		$('#select-fresh').hide();
	} else{
	
	$('#primary div, #primary ul.tabs').hide();
	$('#select-fresh').show();
	}
	return false;
}

function updateFresh () {
	
}

function copyProductAttributes() {
	// what are we sending
	var attributeSourceID = $("option:selected", this).attr("value");

	// clear out all the previously checked attributes
	$('fieldset input:checked').removeAttr("checked");
	// add a loading message
  	$(this).after("<p class='temp-message'>Loading Attributes. One Moment.</p>");

	$.ajax({
		type: "GET",
		dataType: "json",
		url: "/users_products/copyAttributes/" + attributeSourceID,
		success: function(msg){			
			$.each(msg, function(){				
				//find the input with 'this' as its value and check it				
				$("input[value='"+this+"']").attr("checked", "checked");
			});
		},
		error: function(msg){
			alert(msg);
		},
		complete: function(){
			$('.temp-message').remove(); //hide the loading message
		}
		
	});
	
	return false;
}

/*

		generics and resuables

*/

/*
 * $("foo").closer()	
 * attaches a 'close' link to any window. normally just hides the window. to remove it from the dom, add the "remove" param.
 * $("foo").closer("remove") 	
 */
jQuery.fn.closer = function(remove, callback) {
	return this.each(function() {
		var $closeWhat = jQuery(this);
		var closeit = '<a href="#" title="Close this" class="close-window">close</a>';
		$closeWhat.prepend(closeit);
		//var theID = $closeWhat.attr("id");	
		//cl(theID);
			
		//var closeit =	$('<a href="#" title="Close this" class="close-window">close</a>').click(function(){})
				
		jQuery('.close-window').click(function() {
			if(remove)	{ $closeWhat.hide("normal", function(){ $(this).remove(); }); } 
			else 		{ $closeWhat.hide();   }
			if (typeof callback == "function") { callback(); }
			return false;
		});
/*
		jQuery('.close-window').hover(function(){
			cl($(this).parent().attr("id"));
		})
*/

	});	
};

// closer2 not used currently. failed attempt to set speed.
jQuery.fn.closer2 = function(remove, speed, callback) {
	return this.each(function() {
		var $closeWhat = jQuery(this);
		var closeit = '<a href="#" title="Close this" class="close-window">close</a>';
		$closeWhat.prepend(closeit);
		
		//way to catch missing speed param?
		if(typeof speed == "function"){callback = speed; speed = "";}
	
		//set a default
		var closeSpeed = speed.length>2 ? speed : "slow";
		cl(speed + " " + closeSpeed);
		jQuery('.close-window').click(function() {
			//if(remove)	{ $closeWhat.hide().end().remove(); } 
			if(remove)	{ $closeWhat.hide(closeSpeed, function(){ $(this).remove();}); } 
			else 		{ $closeWhat.hide();   }
			if (typeof callback == "function") { callback(); }
			return false;
		});
	});	
};


// confirm modal
// pass in a message and a function to run if the user clicks "yes"
// if Callback is a string, it will redirect on "YES" click.
// 'args' are stuff you can pass to the callback function
// yes and no are button text. (not implemented)
function confirmIt(msg,callback,args,yes,no) {

	jQuery('body').append('<div class="confirm"><p class="confirm-message">Are you Sure</p><a href="#" class="yes" tabindex="1">Yes</a><a href="#" class="confirm-cancel jqmClose" tabindex="2">Cancel</a></div>');
	jQuery(".confirm").jqm({modal:true, overlay: 88});
	
	if(yes)	{ jQuery('.confirm .yes').text(yes);			}
	if(no)	{ jQuery('.confirm .confirm-cancel').text(no);	}
	
  jQuery('.confirm')
    .jqmShow()
    .find('p.confirm-message')
		.html(msg)
    .end()
	.find('.yes')
		.focus()
	.end()	
    .find('a')
      .click(function(){
        if(this.className == 'yes'){			
			if(typeof callback == 'string'){ 
				 window.location.href = callback;
			} else if (args){
				callback(args);
			} else {
				callback();
			}
					
		}	
        $('.confirm').jqmHide().remove();
      });
};

//confirm modal
// same as above but with less action.
function confirm(msg, callback) {
	
	jQuery('body').append('<div class="confirm"><p class="confirm-message"></p><a href="#" class="yes" tabindex="1">Yes</a><a href="#" class="confirm-cancel jqmClose" tabindex="2">Cancel</a></div>');
	jQuery(".confirm").jqm({modal:true, overlay: 88, trigger: false});

  $('.confirm')
    .jqmShow()
    .find('p.confirm-message')
      .html(msg).focus()
    .end()
    .find('a')
      .click(function(){
        if(this.className == 'yes'){			
			(typeof callback == 'string') 
					? window.location.href = callback 
					: callback();
		}
        $('.confirm').jqmHide().remove();
      });
}



function checkRegistration(){
	var errors = false;
	
	if($('#jj993j2f2j3l').val() != ""){
		cl("that's not empty");
	}else{
		cl("empty!");
	}
	
	
	//how are our passwords?
	var pass1 = $('#UserPassword').val();
	var pass2 = $('#UserPasswordConfirm').val();
				
	if (pass1 != pass2) {
		$('#UserPasswordConfirm').focus().parents("div.input").addClass("error");
		$('#UserPasswordConfirm').prev("label").text("Your passwords didn't match.");
		errors = true;
	}
	else{
		$('#UserPasswordConfirm').focus().parents("div.input").removeClass("error");
		$('#UserPasswordConfirm').prev("label").text("Your passwords match.");
	};
	
	// you. must. comply.
	if($('#tos-agree').attr("checked") != true){
		errors = true;
		if($("#tos-agree-error").length < 1){
			$('#tos-agree').parents("fieldset.checkradio").addClass("error").prepend('<label for="tos-agree" id="tos-agree-error" class="error">You must read and agree to the FoodHub Terms of Service</label>');
			//$('#tos-agree').hide();
		}
	}
	
	// if you comply, let's be polite.
	if($('#tos-agree').attr("checked") == true){
		$("#tos-agree").parents("label").next("label.error").hide();
		$("#tos-agree").parents("label").parent(".checkradio").removeClass("error");
	}	
	
	// nothing can be empty. well, nothing with a label. 
	$("label abbr").parents("label").next(":input").each(function() {
		if ($(this).val() == "") {
			errors = true;
			$(this).parents("div.input").addClass("error");
		}
		else{
			$(this).parents("div.input").removeClass("error");
		}
	});
	
	
	// is that a real(ish) email?
	var email = $('#UserEmail').val();
	if(email != "")
	{
		if(isValidEmailAddress(email) != true)
		{
			$('#UserEmail').parents("div.input").addClass("error");	
			$('#UserEmail').prev("label").text("Looks like this isn't a valid email address.");
			errors = true;
		}
	}		

	
	// if anything failed, you. shall. not. pass.
	if (errors == true){
		var firstError = $(this).find(".error:eq(0)"); //.focus();	//focus on the first error
		IX_scrollPage(firstError, 'fast');
		$(this).addClass("errors");
		return false; 
	}
	
}


function setCounties(){
	var $this = $(this);
	var selected = $this.find(":selected").text();
	//var countyFocus = $('#LocationCounty').find("optgroup[label="+selected+"] option:first")
	$('#LocationCounty').find("optgroup[label="+selected+"] option:first").attr("selected", "selected");
}

function IX_scrollPage(target, speed){
	speed != "" ? speed : speed = fast;
	$('html, body').animate({
		scrollTop: $(target).offset().top
	}, speed);
}

function toggleWidgets(e){
	$(e.target).parent('h2').next('.content').slideToggle().end().end().parents('.widget').toggleClass("closed");
}

function redirect(location){
	window.location.href = location;
}

// returns true if email is valid.
function isValidEmailAddress(emailAddress) {
	var pattern = new RegExp(/^(("[\w-\s]+")|([\w-]+(?:\.[\w-]+)*)|("[\w-\s]+")([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i);
	return pattern.test(emailAddress);
}


// clean console.log
function cl(){ if(window.console&&window.console.firebug) { var args = [].splice.call(arguments,0); console.log(args.join(" ")); } }//cl()
// example: cl("If you use cl() instead of console.log(), it won't break IE when you forget to take it out.");



// if exists, jq style.
// if ($('#foo').exists()){ action! }
jQuery.fn.exists = function(){return jQuery(this).length;};

// attach to an input, grab its label, insert the label into the input, hide the label.  
jQuery.fn.inputSetter = function(lower) {	
	return this.each(function() {
		var $input = $(this);
		var $label = $("label[for='"+$input.attr("id")+"']");
		var labeltext = lower && lower==1 ? $label.text().toLowerCase() : $label.text();
		$label.hide();	
		$input.val(labeltext);		
		$input.focus(function() { if (this.value == labeltext) { this.value = ""; }	})
			  .blur(function() { if (!this.value.length) { this.value = labeltext; } });		
	});
};

// generic tab builder
jQuery.fn.idTabs = function() {	
	return this.each(function() {
		var $container = jQuery(this), 
			tabs = $("a", this),
	 		panes = new Array();
		
		tabs.each(function () {
			var $this = jQuery(this);
						
			// using the href to make the collection of panes			
			var pane = $this.attr('href');
			if (pane.indexOf("#") != 0) {
				return true;
			};
		 	panes.push(pane);
		
			
			$this.bind("click", function(){
				//build the jq selector. cheap.
				$(panes.join(",")).hide();
				
				//do some class switching
				$container.find('.active').removeClass('active');
				$this.parent("li").addClass("active");

				$(pane).show();
				return false;
			});
		});
		
		var $default = jQuery('a.default',$container).length 
						? jQuery('a.default',$container) 
						: jQuery('a:first',$container);
	
		$default.click();
		
		
		
		
	});
};


// @shuffler
// fake search results. kept for prototype integrity.
jQuery.fn.shuffleResults = function(shufflee) {	
	return this.each(function() {
		var $wrap = jQuery(this);
		var $shufflewhat = jQuery($wrap).find(shufflee).not(shufflee+" "+shufflee);
		var shuffled = shuffle($shufflewhat);
		
		
		//fade and height junk needs to be an option				
		//don't jump! only needed if fades
		var curHeight = $wrap.css("height");
		$wrap.css("height", curHeight);

		//fades nonsense
		jQuery($shufflewhat).fadeOut(300,function(){
			//could extend to include var htmlElement and var loadingText
			var loader = '<h2 class="loader">Loading...</h2>';
			$wrap.html(loader);
			$wrap.find("h2").fadeTo(500, 1, function(){
				jQuery($shufflewhat).show();
				$wrap.html(shuffled);
			});
		});

		function shuffle(o){ //v1.0
			for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
			return o;
		};
	});
}; // shuffleResults()
	
//update text somewhere else.	
jQuery.fn.changeText = function(updatee) {	
	return this.each(function() {
		var newText = $(this).text();
		$(updatee).text(newText);
	});
};

//for replies, we want the cursor at postition 1, not the end of the text.
jQuery.fn.setCursorPosition = function(pos) {
	if (jQuery(this).get(0).setSelectionRange) {
		jQuery(this).get(0).setSelectionRange(pos, pos);
	} 
	else if (jQuery(this).get(0).createTextRange) {
		var range = jQuery(this).get(0).createTextRange();
		range.collapse(true);
		range.moveEnd('character', pos);
		range.moveStart('character', pos);
		range.select();
	}
};


//character counter for textareas
// requires a label with the quanity in a span <label class="charactersremaining" for="mytextareaid"><span>250</span> characters remaining</label>
// attach it like so: $(".charactersremaining").charactersRemaining();
jQuery.fn.charactersRemaining = function() {
	
    // prevent elem has no properties error
    if (this.length === 0) { return(this); }	
	
	function cr($obj) {

		var counter = {
			
			$target	 	: jQuery("#"+$obj.attr('for')),
			$span		: $obj.find("span:first"),
			maxvalue 	: $obj.children('span:first').text(),
			remaining	: null,
			
			init : function() {
				counter.remaining = counter.maxvalue - counter.$target.val().length;
				counter.$span.text(counter.remaining);
				counter.$target.bind("keyup keydown",counter.tally);			
			},
			
			tally : function() {
								
				if (counter.$target.val().length > counter.maxvalue) { 
					counter.$target.val(counter.$target.val().substring(0, counter.maxvalue));
				}
				counter.$span.text(counter.maxvalue - counter.$target.val().length);
				
			}
			
		};

		// init the counter
		counter.init($obj);

	};
	
	// return jquery - create new cr instance
	return this.each(function() {
		new cr(jQuery(this));		
	});	
	
};

// create open/close. receives dl.
var enableExpand = function(el) {
	$(el).addClass("expander").find("dd").hide().end()
		.find("dt").prepend('<a  class="toggle" href="#">+</a>').click(function(){
			var textinsert = $("a.toggle",this).text() == "+" ? "-" : "+";
			$(this).toggleClass("open").next("dd").slideToggle("fast").end()
			.find("a.toggle").text(textinsert);			
		}).hover(function(){
			$("a",this).addClass("hover"); $(this).addClass("hover"); }, function(){ $("a",this).removeClass("hover"); $(this).removeClass("hover");
		}).find("a.toggle").click(function(){ $(this).parents("dt").click(); return false; });		
};


/*
	
	@breakingNonSpace
	
	Careful -- this seems broken with the latest jQuery...
	
	10.03.08 - pdf
	
	Breaking Non-Space
	
	Insert either &#8203; character or <wbr> tag for < IE7 to allow line
	break in the middle of email address, url, etc.
	
	apply bnsp to choosen elements.
	takes optional array of characters to break at which replaces the defaults,
	just be careful of regex special characters: $("a").bnsp(["$","domain"]);
	$(".bnsp a").bnsp();
	$(".bnsp li").bnsp(["sis","best","name"]);

*/
jQuery.fn.sniff=function(e){var d,a,c=function(g){var f=navigator.userAgent.toLowerCase();f=f.substring(f.indexOf(g+"/")+(g.length+1));return f.substring(0,1);};jQuery.browser.chrome=/chrome/.test(navigator.userAgent.toLowerCase());if($.browser.msie){d="ie ie"+jQuery.browser.version.substring(0,1);}else{if($.browser.mozilla){if(navigator.userAgent.toLowerCase().indexOf("firefox")!=-1){var b=c("firefox")==3&&!!document.createElement("video").canPlayType?"3-5":"3";d="ff ff"+b;}else{d="mz";}}else{if($.browser.chrome){d="ch ch"+c("chrome");$.browser.safari=false;}else{if($.browser.safari){d="sf sf"+c("version");}else{if($.browser.opera){d="op";}}}}}if(navigator.platform.indexOf("Win")!=-1){a="windows";}else{if(navigator.platform.indexOf("Mac")!=-1){a="mac";}else{if(navigator.platform.indexOf("Linux")!=-1){a="linux";}}}return this.each(function(){jQuery(this).addClass(a+" "+d);});};
jQuery.fn.bnsp = function(options) {	
	// if array of characters, use it. else use default set.
	var c = options || ["@","/"];	
	// set bnsp entity based on browser support
	var b = jQuery.browser.msie && jQuery.browser.version < 7 ? "<wbr>" : "&#8203;";	
	// loop and return
	return this.each(function() {		
		var $this = jQuery(this); // store $(this) for use inside another function		
		// loop through each item in character array
		jQuery.each(c, function() {
			var rx = new RegExp(this,'g'); // create new regex object with current character
			$this.html($this.html().replace(rx,this+b)); // replace character with itself + nbsp entity
		}); // end array loop		
	});// end return
}; // end bnsp

// end breakingNonSpace

//browser sniffing to insert body classes. only use for css! except...
// var sniff set to be a global var for conditional testing for ie.
jQuery.fn.sniff=function(s){var platform,v=function(s){var ua=navigator.userAgent.toLowerCase();ua=ua.substring(ua.indexOf(s+'/')+(s.length+1));return ua.substring(0,1);};jQuery.browser.chrome=/chrome/.test(navigator.userAgent.toLowerCase());if($.browser.msie){snuff="ie ie"+jQuery.browser.version.substring(0,1);}
	else if($.browser.mozilla){if(navigator.userAgent.toLowerCase().indexOf('firefox')!=-1){var temp=v("firefox")==3&&!!document.createElement('video').canPlayType?"3-5":v("firefox");snuff="ff ff"+temp;}
	else{snuff="mz";}}
	else if($.browser.chrome){snuff="ch ch"+v("chrome");$.browser.safari=false;}
	else if($.browser.safari){snuff="sf sf"+v("version");}
	else if($.browser.opera){snuff="op";}
	if(navigator.platform.indexOf("Win")!=-1){platform="windows";}
	else if(navigator.platform.indexOf("Mac")!=-1){platform="mac";}
	else if(navigator.platform.indexOf("Linux")!=-1){platform="linux";}

	
	return this.each(function(){jQuery(this).addClass(platform+" "+snuff);});
};

//get text nodes
jQuery.fn.extend({
   textNodes: function() {
      return jQuery(
         jQuery.map( this, function(n){
            return jQuery.grep(n.childNodes, function(n) {
               return n.nodeType == 3;
            });
         })
      );
   }
});





/*
TEMP!! for marketplace prototyping
*/

jQuery(function($) {
	$('.page-marketplace .sorted-by a').click(function(){
		$('.page-marketplace .sorted-by').find('.active').removeClass('active');
		$(this).addClass('active');
		
		$('table tbody').shuffleResults('tr');
		return false;	
	});
});//jQuery ready
