/*
function getPlaceFromFlickr(lat,lon,callback){
   // the YQL statement
   var yql = 'select * from flickr.places where lat='+lat+' and lon='+lon;

   // assembling the YQL webservice API
   var url = 'http://query.yahooapis.com/v1/public/yql?q='+
              encodeURIComponent(yql)+'&format=json&diagnostics='+
              'false&callback='+callback;

   // create a new script node and add it to the document
   var s = document.createElement('script');
   s.setAttribute('src',url);
   document.getElementsByTagName('head')[0].appendChild(s);
};

 // callback in case there is a place found
function output(o){
   if(typeof(o.query.results.places.place) != 'undefined'){
     alert(o.query.results.places.place.name);
   }
}

 // call the function with my current lat/lon
 //getPlaceFromFlickr(37.416115,-122.02456,'output');
*/


/**
 * Closer
 * @author: Will Moore
 * @updated: 1/7/2011
 * pass something, it gets a close button. Think it'll explode if there are two on a page.
 * 
 */
function closer($target, remove){
	var link = '<a class="closer ui-icon" title="Close this window">X</a>';
	$target.prepend(link);

	$('.closer', $target).live('click', function() {
		if(remove == "remove"){
			$target.remove();
		}else{
			$target.hide();
		}
	});


}


/*
 * incompleteFormWarning 0.1
 * wmoore 6/11
 * 
 * warn the user if a form is incomplete before leaving the page
 * 
 */
(function($) {

    $.fn.incompleteFormWarning = function(options) {
        // plugin default options
        var defaults = {
			
		};
		var $el = jQuery(this);
        // extends defaults with options provided
        if (options) {
            $.extend(defaults, options);
        }

		function removeCheck() { 
			alertSet = true;
			window.onbeforeunload = null; 
		}

        // iterate over matched elements
        return this.each(function() {
			var $t = jQuery(this);
			
			// if there is no ajax submit, ensure that the warning doesn't come up when 
			// the page is changed due to form submission.
			$('button, button span, [type="submit"]', $t).live('click', function(){
				removeCheck();
			});
			
			var alertSet = false;
			
			// detect the first change only
			$t.find(':input').one('change', function(){
				// if(window.onbeforeunload){
				// 	window.onbeforeunload = function(e) {
				// 		e = e || window.event;
				// 		if (e) { //FF and IE
				// 		                    e.returnValue = _t['addFormExitConfirm'];
				// 		                }
				// 		                // For Webkit
				// 			            return _t['addFormExitConfirm'];
				// 			        }
				// 
				// }else{
				
					if(!alertSet){
						// ios doesn't fire the window.onbeforeunload event	
						// TODO this should be an option
						$('body').delegate("a", "click", function(e){
							if(!$(this).is('.lang-link')){
								var omg = confirm(_t['formExitConfirm']);
								if (!omg){
									$('.ui-btn-active').removeClass('ui-btn-active');	
									e.preventDefault();
									e.stopPropagation();
									e.stopImmediatePropagation();
								}
							}	
						});
						alertSet = true;
					}
				
			});
        });



    };


})(jQuery);


/**
* labelifier: Move a label into its input
* @author: Will Moore
* @updated: 11/17/2010
*
* @notes: 
* TODO: Haven't inplemented options yet
* TODO: Um, totally fails if there is no for attribute
* 
*/


(function($){
    $.labelifier = function(el, options){
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;

        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;

        // Add a reverse reference to the DOM object
        base.$el.data("labelifier", base);

        base.init = function(){
            base.options = $.extend({},$.labelifier.defaultOptions, options);

            base.labelIt(base.$el);
        };

        base.labelIt = function(el){
        	var $el	= el,
				elID	= $el.attr('id'),
				$label	= $('label[for='+elID+']'),
				text	= $label.text(),
				input	= $el.attr('for') ? $el.attr('for') : "password";
				$input	= $('#'+input);

			$label.hide();
			
			//_debug('no placeholder');
			$el.each(function(){
				$this = $(this);
				
				/*
					if $input is a select
					elif $input is textarea
					elif $input is radio,check... (return?)
					el if $input is input
				*/
				if($this.is('select,[type=radio],[type=checkbox]')){
					$this.prev('label').show();
					return;
				}
				if($this.val() === ""){
					$this.val(text);
				}
				$this.focus(function  () {
					if($this.val() === text) {
				      $this.val('');
				    }
				});
			 	$this.blur(function() {
					if($this.val() === '') {
						$this.val(text);
						$(this).removeClass('changed');
					}else{
						$(this).addClass('changed');
					}
			  	});
			});
        };

        // Run initializer
        base.init();
    };

    $.labelifier.defaultOptions = {
        focusClass: "focused"
    };

    $.fn.labelifier = function(options){
        return this.each(function(){
            (new $.labelifier(this, options));
        });
    };

})(jQuery);




//http://stackoverflow.com/questions/570960/how-to-debug-javascript-jquery-event-bindings-with-firebug-or-similar-tool
$.fn.listHandlers = function(events, outputFunction) {
    return this.each(function(i){
        var elem = this,
            dEvents = $(this).data('events');
        if (!dEvents) {return;}
        $.each(dEvents, function(name, handler){
            if((new RegExp('^(' + (events === '*' ? '.+' : events.replace(',','|').replace(/^on/i,'')) + ')$' ,'i')).test(name)) {
               $.each(handler, function(i,handler){
                   outputFunction(elem, '\n' + i + ': [' + name + '] : ' + handler );
               });
           }
        });
    });
};

window.log = function(){
  log.history = log.history || [];   
  log.history.push(arguments);
  if(this.console){
    console.log( Array.prototype.slice.call(arguments) );
  }
};
function cl(a) {
	if(window.console){
		console.log( a );
	}
}
function cd(a){
	if(window.console){
		console.dir( a );
	}
}




/**
 * DEBUGGER
 * 
 * Heavily 'inspired' by jqtouch's debugger.
 * pass the string 'delta' to it to see the amount of time between two calls
 * 
 */
debug=true;
lastTime=0;
function _debug(message, option) {
	if(debug){
		var d = new Date,
	    	hours = d.getMinutes(),
			secs = d.getSeconds(),
			msecs= d.getMilliseconds(),
			time = hours + ':' + secs + ':' + msecs;
			
		now = (new Date).getTime();
		lastTime = lastTime || 0;
    	delta = now - lastTime;

	    lastTime = now;

		var label = (option == "delta") ? "Time: " + delta + "ms" : time; 

	    if (window.console) {
	        if (message) {
				if ((typeof message == "object" || typeof message == "array") && !message.jquery   ){ //default to console.dir for objects
					console.log(label);
					console.dir(message);					
				} else{
					console.log(label, message);			
				}
	        } else {
	            console.log(label + ': ' + 'Called ' + arguments.callee.caller.name);
	        }
	    }
	}
}




/*
 * $.inJSON utility
 *
 * Searches arbitrary JSON for a key and returns an array of all matches.
 * Intended for use with jQuery 1.4.2
 *
 * Copyright (c) 2010 Dan Connor
 * www.danconnor.com
 *
 * Dual-licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
*/
/*
$.extend($, {
    inJSON: function(json, key) {
        var hit, hits = [];
        $.each(json, function(k, v) {
            if (k === key) hits.push(v);
            if (typeof(v) === "string") {
                return true;
            } else if ($.isArray(v) || $.isPlainObject(v)) {
                var r = $.inJSON(v, key);
                if (r.length > 0) hits = hits.concat(r);
            }
        });
        return hits;
    }
});
*/

/*
	FORM VALIDATION
*/
// http://webcloud.se/log/Form-validation-with-jQuery-from-scratch/
(function($) {
    /*
    * Validation Singleton
    */

    var Validation = function() {
        
        var rules = {
            //can be extended via public .addRule method
            email : {
               check: function(value) {
                   if(value)
                       // return testPattern(value,"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b");
                       // return testPattern(value,"^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i");
                       return testPattern(value,"[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]+");
                   return true;
               },
               	msg : _t["validEmailError"],
				msgSP: _t["validEmailError"]
            },
            url : {
               check : function(value) {

                   if(value)
                       return testPattern(value,"https?://(.+\.)+.{2,4}(/.*)?");
                   return true;
               },
				msg : "Please enter a valid URL.",
				msgSP: "Por favor, NEED SPANISH ERROR."
            },
            number : {
          		check : function(value) {
					if(value)
						return testPattern(value,"^(0?[0-9]?[0-9]|[1-9][0-9]|[1-9][0-9][0-9])$");
					return true;
				},
               	msg : "Please enter a valid number.",
				msgSP: "Por favor, enter a valid number."
            },
            numbernotzero : {
               check : function(value) {
                   if(value)
                       return testPattern(value,"^(0{0,2}[1-9]|0?[1-9][0-9]|[1-9][0-9][0-9])$");
                   return true;
               },
               	msg : "Please enter a valid number (1-999).",
				msgSP: "Por favor, NEED SPANISH ERROR."

            },
            lengthFive : {
               check: function(value) {
	
                  	if(value === "" || value.length == 5){
                    	return true;
					}
                  	else{
                    	return false;
					}
               },
              	msg : _t["zipCodeError"],
				msgSP: _t["zipCodeError"]
            },
            notfirstoption : {
               check: function(value) {
                   if(value)
                       return true;
                   else
                       return false;
               },
              	msg : _t["addFormCategoryError"],
				msgSP: _t["addFormCategoryError"]
            },
            required : {
               check: function(value) {
                   if(value)
                       return true;
                   else
                       return false;
               },
               	msg : _t["requiredError"],
				msgSP: _t["requiredError"]

            }
        };
        var testPattern = function(value, pattern) {

            var regExp = new RegExp("^"+pattern+"$","");
            return regExp.test(value);
        };
        return { //public
            addRule : function(name, rule) {

                rules[name] = rule;
            },
            getRule : function(name) {

                return rules[name];
            }
        };
    }; //validation object
    
    /* 
    * Form factory 
    */
    var Form = function(form) {

        var fields = [];
    	// get all of the form elements
		//$(form[0].elements).each(function(e, a) { //IE 6-8 would't accept this. bizarre.
		$("form:first :input").each(function(e, a) {
            var field = $(this);

			//only ones with rel attributes
            if(field.attr('rel') !== undefined) {
                fields.push(new Field(field));
            }

        });
        this.fields = fields;
    };

    Form.prototype = {
        validate : function() {
			
            for(field in this.fields) {
                this.fields[field].validate();
            }
        },
        isValid : function() {
            
            for(field in this.fields) {
                
                if(!this.fields[field].valid) {
            
                    this.fields[field].field.focus();
                    return false;
                }
            }
			
            return true;
        }
    };
    
    /* 
    * Field factory 
    */
    var Field = function(field) {

        this.field = field;
        this.valid = false;
        this.attach("change");
    };


    Field.prototype = {
        
        attach : function(event) {
        
            var obj = this;
            if(event == "change") {
                obj.field.bind("change",function() {
                    return obj.validate();
                });
            }
            if(event == "keyup") {
                obj.field.bind("keyup",function(e) {
                    return obj.validate();
                });
            }
        },
        validate : function() {
            
            var obj = this,
				//obj.field is a reference to the field propery of the field object (which is passed in by reference. confusing name.)
                field = obj.field,
                errorClass = "error-list",
                errorlist = $(document.createElement("ul")).addClass(errorClass),
                types = field.attr("rel").split(" "), 
                container = field.parents('li'), // specific to HLT. should be SETable.
                errors = []; 

            

            container.find(".error-list").remove();

            for (var type in types) {
				
				 // Get the rule object from our Validation object.
                var rule = $.Validation.getRule(types[type]);

				//the rule object has the .check method
                if(!rule.check(field.val())) {

                    container.addClass("error");
					
					//language check
					if(B.local == "sp"){
						errors.push(rule.msgSP);
                    	
					} else{
                    	errors.push(rule.msg);
					}
                }
            }
            if(errors.length) {
				
                obj.field.unbind("keyup");
				// .attach is a method of the field prototype. it binds keyup to the validation method (on the field);
                obj.attach("keyup");
                container.prepend(errorlist.empty());
                for(error in errors) {
                    errorlist.append("<li>"+ errors[error] +"</li>");        
                }
                obj.valid = false;

				$('button.active').removeClass('active');
            } 
            else {
                errorlist.remove();
                container.removeClass("error");
                obj.valid = true;
            }
        }
    };
	
    /*
    * Validation extends jQuery prototype
    */
    $.extend($.fn, {
        
        validation : function() {
            var validator = new Form($(this));
            $.data($(this)[0], 'validator', validator);
            
            $(this).live("submit", function(e) {
				//radioValidate($(this));
				
                validator.validate();

                if(!validator.isValid()) {
                    e.preventDefault();
                }

            });
        },
        validate : function() {
            
            var validator = $.data($(this)[0], 'validator');
            validator.validate();
            return validator.isValid();
            
        }
    });
    $.Validation = new Validation();

})(jQuery);


/**
*    Json key/value autocomplete for jQuery 
*    Provides a transparent way to have key/value autocomplete
*    Copyright (C) 2008 Ziadin Givan www.CodeAssembly.com  (http://codeassembly.com/Unobtrusive-jQuery-autocomplete-plugin-with-json-key-value-support/)
*    Modifications by Will Moore @ One Economy Corp
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Lesser General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU Lesser General Public License
*    along with this program.  If not, see http://www.gnu.org/licenses/
*    
*    Examples 
*	 $("input#example").autocomplete("autocomplete.php");//using default parameters
*	 $("input#example").autocomplete("autocomplete.php",{minChars:3,timeout:3000,validSelection:false,parameters:{'myparam':'myvalue'},before : function(input,text) {},after : function(input,text) {}});
*    minChars = Minimum characters the input must have for the ajax request to be made
*	 timeOut = Number of miliseconds passed after user entered text to make the ajax request   
*    validSelection = If set to true then will invalidate (set to empty) the value field if the text is not selected (or modified) from the list of items.
*    parameters = Custom parameters to be passed
*    after, before = a function that will be caled before/after the ajax request
*/

jQuery.fn.autocomplete = function(url, settings ) 
{
	return this.each( function()//do it for each matched element
	{
		//this is the original input
		var textInput = $(this);
		var tID = textInput.attr('id');
		var form = textInput.parents('form').css('position', 'relative');
		
		//create a new hidden input that will be used for holding the return value when posting the form, then swap names with the original input
		textInput.after('<input type=hidden name="' + textInput.attr("name") + '"/>').attr("name", textInput.attr("name") + "_text");
		textInput.attr('autocomplete','off');
		
		var valueInput = $(this).next();

	    //make sure the input php cares about is populated.
        textInput.change(function(){
           $(this).next('input').val($(this).val()); 
        });

        //create the ul that will hold the text and values
		valueInput.after('<ul class="autocomplete" style="display: none"></ul>');
		var list = valueInput.next().css({ width: textInput.width() + 8});
		var oldText = '';
		var typingTimeout = tID;
		var size = 0;
		var selected = 0;
		var changed = false;
		
		settings = jQuery.extend(//provide default settings
		{
			minChars : 1,
			timeout: 1000,
			after : null,
			before : null,
			onselect: null,
			validSelection : true,
			parameters : {'inputName' : valueInput.attr('name'), 'inputId' : textInput.attr('id')}
		} , settings);

		function getData(text)
		{
			window.clearInterval(typingTimeout);
			if (text != oldText && (settings.minChars !== null && text.length >= settings.minChars))
			{
				clear();
				if (typeof settings.before == "function") 
				{
					settings.before(textInput,text);
				}
				textInput.addClass('autocomplete-loading');
				settings.parameters.search = text;
				
                $.getJSON(url, settings.parameters, function(ret)
				{
					if(!ret){
						return;
					}	
					var data = ret.data;
					var items = '';
					if (data)
					{
						var niceName;
						size = data.length;
						changed = false;
						$('#location-overlay').css("height", "450px");
						
						$(data).each(function(i){
							// they're all in the US for now.
							niceName = data[i].longname;
							niceName = niceName.replace(', United States','');

							items += '<li value="'+ data[i].zipcode +'">'+niceName+'</li>';
						});
						
						// Insert the list items and attach events to them.	
						list.html(items);
						list.show().children()
							.hover(function() { 
								$(this).addClass("selected").siblings().removeClass("selected");
								}, function() { $(this).removeClass("selected"); } 
							)
							.click(function () {
								valueInput.val( $(this).attr('value') );
								textInput.val( $(this).text() );
								
								//fix for zips that start with 0
								if (valueInput.val().length === 4) {
									valueInput.val('0'+valueInput.val());
								}
								 
								clear();

								if (typeof settings.onselect == "function"){
									 settings.onselect(valueInput.val(),textInput.val());
								}
							});
						// make sure the list goes away when the input loses focus
							// REMOVED 8/15/11 because of chrome errors. Firing 'blur' when a user scrolls.
						// textInput.blur(function(e) {
						// textInput.parents('.form-set-location').blur(function(e) {
						//     if(jQuery('.autocomplete:has(.selected)').length === 0){
						//         console.log('blur');
						//         clear();
						//     } 
						// });

						// run the callback	
						if (typeof settings.after == "function"){
							settings.after(textInput,text);
						}
					}
					textInput.removeClass('autocomplete-loading');
				});
				oldText = text;
			}
		}

		
		function clear()
		{
			list.hide();
			size = 0;
			selected = 0;
			changed = false;
		}	
		// hide the box when you click outside of the automcomplete area.
		$("body").live('click', function (e){
			var $t = $(e.target);
			if($('.autocomplete>li').length > 1){
				if($t.parents('.form-set-location').length > 1){
					return;
				}else{
					clear();
				}
			}
		});


		textInput.keydown(function(e) 
		{
			window.clearInterval(typingTimeout);
			if(e.which == 27)//escape
			{
				clear();
			} else if (e.which == 46 || e.which == 8)//delete and backspace
			{
				clear();
				//invalidate previous selection
				if (settings.validSelection) valueInput.val('');
			}
			else if(e.which == 13)//enter 
			{ 
				if ( list.css("display") == "none")//if the list is not visible then make a new request, otherwise hide the list
				{ 
					$(this).next('input').val($(this).val()).closest('form').submit();
					//getData(textInput.val());
				} else
				{
					if (typeof settings.onselect == "function"){
						
						
						if (valueInput.val().length === 4) {
							valueInput.val('0'+valueInput.val());
						}
						 settings.onselect(valueInput.val(),textInput.val());
					}
					clear();
				}
				e.preventDefault();
				return false;
			}
			// else if(e.which == 40 || e.which == 9 || e.which == 38)//move up, down 
			else if(e.which == 40 || e.which == 38)//move up, down 
			{
			  switch(e.which) 
			  {
				case 40: //down
				case 9:
				  	selected = selected >= size - 1 || !changed ? 0 : selected + 1; 
					changed = true;					
					// cheap way to keep the above simple but start with 0
					break;
				case 38:
				  selected = selected <= 0 ? size - 1 : selected - 1; break;
				default: break;
			  }
			  //set selected item and input values
			  textInput.val( list.children().removeClass('selected').eq(selected).addClass('selected').text() );	        
			  valueInput.val( list.children().eq(selected).attr('value') );
				//tab fix?
				//if (e.which == 9) clear();
			
			} else 
			{ 
				// invalidate previous selection
				if (settings.validSelection) valueInput.val('');
				// let zip codes go through
				if(B.tools.isNumber( textInput.val() ) ){
					return;
				}
				typingTimeout = window.setTimeout(function() { 
									getData(textInput.val()); 
								},settings.timeout);
			}
			return true;
		});
	});
};

