
	var rr = {
		captcha: {
			show: function(options) {
				if (typeof options === "undefined") {
					options = {};
				}
				options.url = "/account/ajax/captcha";
				rr.dialog.show(options);
			}
		},
	
		image: {
			upload: function() {
				rr.dialog.show({ url: '/images/ajax' });
				return false;
			},
			remove: function(id) {
				rr.dialog.show({ url: '/images/ajax/remove/id:' + id });
				return false;
			},
			edit: function(id) {
				rr.dialog.show({ url: '/images/ajax/edit/id:' + id });
				return false;
			}
		},
		
		account: {			
			login: function(options) {	
				if (typeof options === "undefined") {
					options = {};
				}
				options.url = '/account/ajax/login';
				rr.dialog.show(options);
				return false;
			},
			create: function(options) {
				if (typeof options === "undefined") {
					options = {};
				}
				options.url = '/account/ajax/create';
				rr.dialog.show(options);
				return false;
			},
			forgot_password: function() {
				rr.dialog.show({ url: '/account/ajax/forgot_password' });
				return false;
			}
		}
	};
	
	rr.ajax = {		
		
		request: function(options) {
			
			var ajax_options = {
				cache: false,
				dataType: 'json',
				type: "POST",
				context: document.body
			};
			
			if (typeof options.popped_options === "object") {
				rr.ajax.popped_options = options.popped_options; 
			} 
			delete options.popped_options;
			
			for (var k in options) {
				if (k.substring(0,1) !== '_') {
					ajax_options[k] = options[k];
				}
			}
			
			var custom_success_handler	= options.success;
			var custom_error_handler	= options.error;
			
			rr.dialog.loading();
			
			//if success exists, wrap it with the default handler
			ajax_options.success = function(response, textStatus, XMLHttpRequest) {					
				if (typeof response === "undefined") {
					response = {};
				}
				
				rr.dialog.not_loading();
				
				if (rr.ajax.handler(response, textStatus, XMLHttpRequest)) {
					return;
				}
				if (typeof custom_success_handler === "function") {
					//extended handling	
					custom_success_handler(response, textStatus, XMLHttpRequest);
				}
			};
			
			//if success exists, wrap it with the default handler
			ajax_options.error = function(response, textStatus, XMLHttpRequest) {					
				if (typeof response === "undefined") {
					response = {};
				}
				rr.dialog.not_loading();
				if (typeof custom_error_handler === "function") {
					custom_error_handler(response, textStatus, XMLHttpRequest);
				}
			};
			
			return $.ajax(ajax_options);
		},
		
		handler: function(response, textStatus, XMLHttpRequest) {					
			if (response === null || typeof response === "undefined") {
				response = {};
			}
				
			if (response.debug) {
				if (console && console.log) {
					console.log(response.debug);
				} else {
					alert(response.debug);
				}
			}
	
			if (response.status) {
				var opts = {};
				if (typeof rr.ajax.popped_options === "object") {
					opts = rr.ajax.popped_options;
				}
				switch (response.status) {
					case 'login':
						rr.account.login(opts);
						return true;
					
					case 'create':
						rr.account.create(opts);
						return true;
					
					case 'captcha':
						rr.captcha.show(opts);
						return true;
						
					case 'fault':
						rr.dialog.alert({
							title: response.title ? response.title : "Error",
							message: {
								body: response.message ? response.message : "There was a problem generating that page",
								css_class: 'error'
							}
						});
						return true;
				}
			}
			
			//then.. redirect needed?
			if (response.redirect === true) {
				location.href = location.href; 
				return true;
			} else if (response.redirect) {
				location.href = response.redirect;
				return true;
			}
						
			return false;
		}
	};
	
	
	rr.dialog = {
					
		show: function(options) {
			
			rr.dialog.__init(options);			
			rr.dialog.__init_containers();
			
			if (options.title) {
				rr.dialog.title(options.title);	
			} else {
				rr.dialog.title("&nbsp;");	
			}
			
			if (rr.dialog.__options.message.body && rr.dialog.__options.message.body.length) {
				// pre-defined dialog
				rr.dialog.__load_message_body();
			} else if (rr.dialog.__options.url && rr.dialog.__options.url.length) {
				// ajax loaded body
				rr.dialog.__load_ajax_body();
			} else {
				rr.dialog.close();
			}
			
			rr.dialog.__show();
						
			//status complete
			rr.dialog.status('loaded');
			
			if (typeof(rr.dialog.__options.onload) === "function") {
				$(window).ready(rr.dialog.__options.onload);
			}

			//on completed loading
			if (rr.dialog.__options.autoclose) {
				setTimeout(rr.dialog.close, rr.dialog.__options.autoclose * 1000);
			}
						
			//doc_body.ready(rr.dialog.__location);
		},
		
		//close this dialog - done on a successful termination of a dialog
		close: function(set) {			
			rr.dialog.status("done");
			if (typeof(rr.dialog.__options.onclose) === "function" && ! rr.dialog.__options.onclose()) {
				return false; //interrupt
			}
			var last = rr.dialog.trail._get();
			if (last !== false) {
				rr.dialog.show(last);
				return false;			
			} else {	
				return rr.dialog.__close();
			}
		},
		
		//close all dialogs - done on the unsuccessful termination of a dialog.
		cancel: function() {
			rr.dialog.status("done");
			if (typeof(rr.dialog.__options.oncancel) === "function" && ! rr.dialog.__options.oncancel()) {
				return false; //interrupt
			}
			return rr.dialog.__close();
		},
			
		//
		// get/set
		//
		
		update: function(options) {
			
			//location
			if (typeof(options.width) !== "undefined" || typeof(options.height) !== "undefined") {
				if (options.width > 0) {
					rr.dialog.width(options.width);
				}
				if (options.height > 0) {
					rr.dialog.height(options.height);
				}
				rr.dialog.__location();
			}
			
			if (typeof(options.title) !== "undefined") {
				rr.dialog.title(options.title);
			}
			
			if (typeof(options.trailme) !== "undefined") {
				rr.dialog.__options.trailme = options.trailme;
			}
			
			if (typeof(options.oncancel) !== "undefined") {
				rr.dialog.__options.oncancel = options.oncancel;
			}
			
			if (typeof(options.onclose) !== "undefined") {
				rr.dialog.__options.onclose = options.onclose;
			}
			
			if (typeof(options.oncloseall) !== "undefined") {
				rr.dialog.__options.oncloseall = options.oncloseall;
			}
			
			if (typeof(options.closekeys) !== "undefined") {
				rr.dialog.__options.closekeys = options.closekeys;
			}
		},
		
		status: function(status) {
			if (typeof(status) !== "undefined") {
				rr.dialog.__status = status;
			} else {
				return rr.dialog.__status;
			}
		},
		
		body: function(body) {
		
			if (! rr.dialog.__containers.body) {
				return null;
			}
			
			if (typeof(body) !== "undefined") {			
				rr.dialog.__containers.body.removeClass();
				rr.dialog.__containers.body.html(body);
				rr.dialog.__location();
			} else {
				return rr.dialog.__containers.body.html();
			}
		},
		
		title: function(title) {
			if (! rr.dialog.__containers.title) {
				return null;
			}
			
			if (typeof(title) !== "undefined") {
				return rr.dialog.__containers.title.html(title);
			} else {
				return rr.dialog.__containers.title.html();
			}
		},		
		
		oncancel: function(func) {
			if (typeof(func) === "function") {
				rr.dialog.__options.oncancel = func;
			} else {
				return rr.dialog.__options.oncancel;
			}
		},
		
		onclose: function(func) {
			if (typeof(func) === "function") {
				rr.dialog.__options.onclose = func;
			} else {
				return rr.dialog.__options.onclose;
			}
		},
		
		width: function(width) {
			if (typeof(width) !== "undefined") {
				rr.dialog.__containers.body.width(width);
			} else {
				rr.dialog.__containers.body.width();
			}
		},
		
		height: function(height) {
			if (typeof(height) !== "undefined") {
				rr.dialog.__containers.body.height(height);
			} else {
				rr.dialog.__containers.body.height();
			}
		},
		
		//the trail
		trail: {
		
			__arr: [],
			
			_add: function(args) {
				rr.dialog.trail.__arr.push(args);
			},
			
			_get: function() {
				
				while (rr.dialog.trail.__arr.length > 0) {
					var last = rr.dialog.trail.__arr.pop();
					if (last && last.status !== "done") {
						return last.options;
					}
				}
				return false;
			},
			
			pop: function() {
				rr.dialog.trail._get();
			},
			
			count: function() {
				return rr.dialog.trail.__arr.length;
			},
			
			clear: function() {
				rr.dialog.trail.__arr = [];
			}			
		},
		
		loading: function() {
			if (rr.dialog.active) {
				rr.dialog.__containers.loading.css("display", "block");
			}
		},
		
		not_loading: function() {
			if (rr.dialog.active) {
				rr.dialog.__containers.loading.css("display", "none");
			}
		},
		
		alert: function(options) {
			rr.dialog.status("done"); //kill the current window			
			var settings = {
				trailme: false,
				closekeys: [rr.tool.key.ESCAPE, rr.tool.key.ENTER, rr.tool.key.SPACE], //any key
				oncancel: function() {
					rr.dialog.close(); //close instead
					return false; 
				},
				onload: function() {
					$("#popped_okay_button").focus();
				}
			};
					
			rr.dialog.show($.extend(settings, options));
		},
		
		// PRIVATE	
		
		__init: function(options) {
			
			rr.dialog.active = true;
			
			//store the previous dialog if available
			if (rr.dialog.status() !== 'done' && rr.dialog.__options && rr.dialog.__options.trailme === true) {
				rr.dialog.trail._add({
					options: rr.dialog.__options,
					status: rr.dialog.status()
				});
			}
			
			clearTimeout(rr.dialog.close);
			
			//defaults
			rr.dialog.__options = {
				id: null,
				status: null,
				
				//dialog params
				width: 600,
				height: null,
				
				//content
				title: "Alert",
				message: {}, //body, class
				url: null,
				
				//callbacks
				onload: null,
				onclose: null,
				oncancel: null,
				oncloseall: null,
				
				//closers
				trailme: true,
				closekeys: [rr.tool.key.ESCAPE], //esc
				autoclose: false //in seconds
			};
			
			//containers
			if (! rr.dialog.__containers) {
				rr.dialog.__containers = {			
					window: null,
					title: null,
					menu: null,
					body: null,
					loading: null,
					dim: null
				};
			}
						
			rr.dialog.status('loading');
		
			//override defaults
			$.extend(rr.dialog.__options, options);
		},
		
		__location: function() {
			
			if (rr.dialog.__containers && rr.dialog.__containers.window) {
				
				var height	= rr.dialog.__containers.window.height();
				var width	= rr.dialog.__containers.window.width();
				
				if (height > 0 && width > 0) {
				
					var win		= $(window);					
					var top		= parseInt((win.height() / 2) - (height / 2), 10);
					var left	= parseInt((win.width() / 2) - (width / 2), 10);
					
					 //make it a wee bit higher up on the screen
					if (top > 110) {
						top -= 70; 
					}									
					if (top < 0) { 
						top = 0; 
					}
					if (left < 0) { 
						left = 0; 
					}
					
					rr.dialog.__containers.window.css({
						'top': top + 'px',
						'left': left + 'px'
					});
				}
			}
		},
			
		_error: function(message) {
			rr.dialog.status("done"); //kill the current window
			rr.dialog.show({
				title: "Error",
				trailme: false,
				message: {
					body: message,
					css_class: "error"
				},
				closekeys: [rr.tool.key.ESCAPE, rr.tool.key.ENTER, rr.tool.key.SPACE],
				oncancel: function() {
					rr.dialog.close(); //close instead
					return false; 
				},
				onload: function() {
					$("#popped_okay_button").focus();
				}
			});
		},
		
		__show: function() {
			if (rr.dialog.__containers && rr.dialog.__containers.dim && rr.dialog.__containers.dim.css('display') !== 'block') {
				var doc_body = $("body");
				rr.dialog.__containers.dim.appendTo(doc_body).css('filter', 'alpha(opacity=50)').fadeIn('slow'); //opacity bit is an IE hack (it goes to black without this)
				rr.dialog.__containers.window.appendTo(doc_body).fadeIn('fast');
				rr.dialog.__containers.body.focus();
				rr.dialog.__location();
			}
		},
		
		__close: function() {
			
			if (typeof(rr.dialog.__options.oncloseall) === "function" && ! rr.dialog.__options.oncloseall()) {
				return false; //interrupt
			}
			
			rr.dialog.trail.clear();
			rr.dialog.__keypress_unbind();
			
			if (rr.dialog.__containers && rr.dialog.__containers.dim && rr.dialog.__containers.dim.css('display') === 'block') {
				rr.dialog.__containers.dim.fadeOut('fast', function() {
					$(this).remove();
				});
				rr.dialog.__containers.window.fadeOut('fast', function() {
					$(this).remove();
				});
			}
			
			rr.dialog.__containers = null;
			rr.dialog.active = false;
			
			return true;
		},
		
		__init_containers: function() {
		
			var loading = function() {			
				rr.dialog.body('<div class="inner light"><div class="fat bold special">Loading &nbsp; <img src="/public/images/ui/loading.gif" alt="" /></div></div>');	
			};
		
			if (rr.dialog.__containers.body === null) {
								
				rr.dialog.__containers.body		= $("<div></div>");
				rr.dialog.__containers.title	= $("<div></div>");
				rr.dialog.__containers.menu		= $("<div></div>");
				rr.dialog.__containers.dim		= $("<div>&nbsp;</div>");
				rr.dialog.__containers.loading	= $('<img src="/public/images/ui/loading.gif" alt="Loading..." />');
				
				//other parts
				var close_button = $("<div></div>");
				close_button.addClass("close");
				close_button.click(rr.dialog.cancel);
				
				//menu loading image
				rr.dialog.__containers.loading.addClass("menu_loading");
				
				//menu
				rr.dialog.__containers.menu.addClass("inner mini");
				rr.dialog.__containers.menu.append(close_button);
				rr.dialog.__containers.menu.append(rr.dialog.__containers.loading);
				rr.dialog.__containers.menu.append(rr.dialog.__containers.title);
				
				//body		
				rr.dialog.__containers.body.width(rr.dialog.__options.width);
				//rr.dialog.__containers.body.css('overflow', 'auto');
				if (rr.dialog.__options.height) {
					rr.dialog.__containers.body.css('max-height', rr.dialog.__options.height + "px");
				}
				loading();
				
				//assemble
				rr.dialog.__containers.window = $("<div></div>");
				rr.dialog.__containers.window.addClass("popup");
				
				//assemble
				rr.dialog.__containers.window.append(rr.dialog.__containers.menu);
				rr.dialog.__containers.window.append(rr.dialog.__containers.body);
				
				//dimmed background
				rr.dialog.__containers.dim.css('display', 'none');
				rr.dialog.__containers.dim.attr('id', 'dim');
			
				//key press handlers
				rr.dialog.__keypress_bind();
				
				rr.dialog.__show();
			
			} else {
				//reset the width/height
				rr.dialog.__containers.body.width(rr.dialog.__options.width);
				rr.dialog.__containers.body.css('overflow', 'auto');
				if (rr.dialog.__options.height) {
					rr.dialog.__containers.body.css('max-height', rr.dialog.__options.height + "px");
				} else {
					rr.dialog.__containers.body.css('max-height', "auto");
				}
				loading();
			}
		},
		
		__keypress_bind: function() {
			if (! rr.dialog.__keypress_set) {
				//don't bind the key listener instantly - certain keys (eg. return) could be in up/down state while this dialog is loading
				rr.tool.fork(function(){
					$(window).bind("keyup", rr.dialog.__keypress_handler);
				});				
				rr.dialog.__keypress_set = true; //don't set it twice
			}
		},
		
		__keypress_unbind: function() {
			if (rr.dialog.__keypress_set) {
				$(window).unbind("keyup", rr.dialog.__keypress_handler);
				rr.dialog.__keypress_set = false;
			}
		},
		
		__keypress_handler: function(e) {
			var code = e.keyCode || e.which;
			if ($.inArray(code, rr.dialog.__options.closekeys) !== -1) { //esc
				//silly hack. If you do it right away, it'll kill the ajax request for the previous popup.
				rr.tool.fork(rr.dialog.cancel); 
				return false;
			}
		},
		
		//alert style body
		__load_message_body: function() {
				
			var close_button = $('<input type="button" id="popped_okay_button" value="Okay" />');
			close_button.click(rr.dialog.close);
				
			var close_container = $("<div></div>");
			close_container.addClass("inner dark");
			close_container.append(close_button);
			
			var message_body = $("<div></div>");
			if (rr.dialog.__options.message.css_class) {
				message_body.addClass("popbox " + rr.dialog.__options.message.css_class);
			}
			message_body.html(rr.dialog.__options.message.body);

			var body_container = $("<div></div>");
			body_container.addClass("inner light");
			body_container.html(message_body);
			
			rr.dialog.__containers.body.removeClass();
			rr.dialog.__containers.body.html(body_container);
			rr.dialog.__containers.body.append(close_container);
			
			rr.dialog.__location();
			rr.dialog.not_loading();
		},
		
		//dynamically loaded body
		__load_ajax_body: function() {
			
			if (! rr.dialog.__options.url) {
				return rr.dialog._error("No URL given");
			}
			
			//load popup content
		    rr.ajax.request({
				url: rr.dialog.__options.url, 
				success: function(response, textStatus, XMLHttpRequest) {
			
					if (response) {						
						
						//if error, show error
						if (response.status === "error") {
							return rr.dialog._error(response.message ? response.message : 'Your request could not be completed');
						} else {
							if (rr.dialog.__containers.body) {
								rr.dialog.__containers.body.removeClass();
							
								if (response.html && response.html.length) {
									rr.dialog.body(response.html);
								} else {
									return rr.dialog._error("Content not found");
								}
							} else {
								return false;
							}
						}
						
					} else {
						return rr.dialog._error("There seems to have been a problem loading, please close this pop-up and try again.");
					}
					
					rr.dialog.__location();
					
					//add resizers
					$(window).resize(rr.dialog.__location).ready(rr.dialog.__location);						
				},
				error: function(response, textStatus, XMLHttpRequest) {
					return rr.dialog._error("There seems to have been a problem loading, please close this pop-up and try again.");
				}
		    });
		}
	};
	
	rr.nav = {
		go: function(url) {
			history.pushState({}, "", url);
			return false;
		}
	};
	
	rr.tool = {
		
		key: {	        
			ALT: 18,
			BACKSPACE: 8,
			CAPS_LOCK: 20,
			COMMA: 188,
			COMMAND: 91,
			COMMAND_LEFT: 91, // COMMAND
			COMMAND_RIGHT: 93,
			CONTROL: 17,
			DELETE: 46,
			DOWN: 40,
			END: 35,
			ENTER: 13,
			ESCAPE: 27,
			HOME: 36,
			INSERT: 45,
			LEFT: 37,
			MENU: 93, // COMMAND_RIGHT
			NUMPAD_ADD: 107,
			NUMPAD_DECIMAL: 110,
			NUMPAD_DIVIDE: 111,
			NUMPAD_ENTER: 108,
			NUMPAD_MULTIPLY: 106,
			NUMPAD_SUBTRACT: 109,
			PAGE_DOWN: 34,
			PAGE_UP: 33,
			PERIOD: 190,
			RIGHT: 39,
			SHIFT: 16,
			SPACE: 32,
			TAB: 9,
			UP: 38,
			WINDOWS: 91 // COMMAND	        
	    },
		
		fork: function(f) {
			setTimeout(f, 0); //spawns a function in a seperate thread
		},
		
		val_changed: function(input, onchange) {
			
			var last_val = input.val();
						
			var loop = function() {
				var val = input.val();
				if (last_val !== val) {
					onchange(val, last_val);
					last_val = val;
				}
				
				setTimeout(loop, 150);
			};
			
			loop();
		},
		
		forEach: function(obj, f, opt_obj) {  
			for (var k in obj) {  
				if (obj.hasOwnProperty(k)) {  
					f.call(opt_obj, obj[k], k, obj);  
				}  
			}  
		},
		
		isDef: function(val) {  
			var undefined;  
			return val !== undefined;  
		},
		
		keypress_bind: function(object, func) {
			var keypress = window.opera || ( /macintosh/i.test( window.navigator.userAgent ) && $.browser.mozilla )
		
			object.bind(keypress ? 'keypress' : 'keydown', function(e) { func(e.which, e.keyCode); });
			object.bind('submit', function() { func(rr.tool.ENTER, e.keyCode); });
			
			return true;
		},
		
		escape_regex: function(value) {
			return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
		},
		
		filter: function(array, term) {
			var matcher = new RegExp(rr.tool.escape_regex(term), "i");
			return $.grep(array, function(value) {
				return matcher.test(value.name);
			});
		},
		
		text_width: function(str, css) {
			var measure = $("#text_measure");
			
			if (! measure.length) {
				//alert('Creating');
				measure = $("<span id='text_measure'></span>").appendTo("body");
			}
		
			if (css) {
				measure.css(css);
			}
		
			return measure.html(str).width();
		},
		
		//always use onload
		prefilled: function(objs) {
			
			objs.each(function() {
				var t = $(this);
				var val = t.val();
				var prefill = t.attr('title');
				
				if (! val) {
					t.val(prefill);
					val = prefill;
				}
				
				if (val === prefill) {					
					t.addClass("prefilled");
				} else {			
					t.removeClass("prefilled");				
				}
							
				t.focus(function() {
					if (t.val() === t.attr('title')) {
						t.val("")		
						.removeClass("prefilled");
					}
				})
				//.submit(function() {
				//	if (t.val() === t.attr('title')) {
				//		t.val("");
				//	}
				//})
				.blur(function() {
					if (t.val().length === 0) {
						t.val(prefill)
						.addClass("prefilled");
					}
				});
			});
		}
	};

	rr.menu = { 
		create: function(container, button, menu) {
			var active = false;
					
			var load = function() {			
				button.click(function(event) {
					if (active) {
						hide();
					} else {
						show();
					}
					
					return false;
				});
			};
			
			var show = function() {
				active = true;							
				button.addClass('active');
				menu.css('display', 'block');
				
				$(document).bind('click', hide_listener);
			};
			
			var hide = function(event) {
				active = false;
				button.removeClass('active');
				menu.css('display', 'none');
				
				$(document).unbind('click', hide_listener);
			};
			
			var hide_listener = function(event) {
				if (container.has($(event.target)).length > 0) {
					return true;
				}
				
				hide();
			};
			
			load();
		}
	};
	
	rr.button_menu = {				
		listen: function(div, selected, list) {
			var menu = undefined;
			var body_listener = undefined;
			
			var init = function() {
				div.click(function(e){
					e.stopPropagation();
					if (menu) {
						unload_menu();
					} else {
						load_menu();							
					}
				});
			};
			var load_menu = function() {
				menu = $("<ul></ul>")
				.css({
					display: 'none'
				})
				.addClass("menu")
				.click(menu_click);
				
				for (var k in list) {
					var li = $("<li></li>")
					.html(list[k].name)
					.data(list[k])
					.click(menu_click);
					
					if (list[k].id === selected) {
						menu_li_active(li);
					}
					
					menu.append(li);
				}
				
				menu.appendTo(div.parent()).fadeIn('fast');
				$("body").click(unload_menu);
			};
			var unload_menu = function() {
				menu.fadeOut('fast', function(){
					$(this).remove();
					menu = undefined;
				});
				$("body").unbind('click', unload_menu);
			};
			var menu_li_active = function(li) {
				li.addClass("active")
				.append(
					$("<span></span>").addClass("check")
				);
			};
			var menu_li_inactive = function() {						
				menu.find("li.active span.check").remove();
				menu.find("li.active").removeClass("active");
			};
			var menu_click = function(e) {
				e.stopPropagation();
				var li = $(this);
				menu_li_inactive();
				menu_li_active(li);
				var data = li.data();
				if (typeof data.callback === "function") {
					data.callback();
				}
			};
			
			init();
		}
	};
	
	
	//rr.infobox.listen($("#moo"));
	rr.infobox = {				
		listen: function(options) {
			var bubble;
			var wait_timer;
			var init = function() {
				options.target.hover(
					activate, 
					deactivate
				);
				
				default_options = {
					width: 200,
					wait: 0,
					orientation: "botton",
					html: ""
				};
				
				options = $.extend(default_options, options);
			};
			var activate = function() {
				if (options.wait) {
					wait_timer = setTimeout(create_bubble, options.wait);
				} else {
					create_bubble();
				}
			};
			var deactivate = function() {
				if (wait_timer) {
					clearTimeout(wait_timer);
					wait_timer = undefined;
				}
				if (bubble) {
					bubble.remove();
					bubble = undefined;
					//bubble.fadeOut('fast', function(){
					//	$(this).remove();
					//	bubble = undefined;
					//});
				}
			};
			var create_bubble = function(){
				if (typeof bubble === "undefined") {
					bubble_box();
				}
			};
			var bubble_box = function() {
				var bubble_css = options.css ? options.css : {};
				
				switch (options.orientation) {
					case 'top':	
						bubble_css['bottom'] = "12px";
					
						bubble = $("<div/>")
						.addClass("bubble")
						.css(bubble_css)
						.html(
							$("<div/>")
							.append(
								$('<div class="inner"></div>')
								.html(options.html)
								.css({
									"width": options.width + "px"
								})
							)
							.append(
								$("<div/>")
								.css({
									'background': '#000',
									'border-color': 'rgba(0, 0, 0, 0.8) transparent transparent transparent',
									'border-style': 'solid',
									'border-width': '5px',
									'width': 0,
									'height': 0,
									'margin': '0 0 0 14px'
								})
							)
						)
						.appendTo(options.target)
						.fadeIn('fast');
						break;
						
					case 'right':
						bubble_css['top'] = "-4px";
						bubble_css['right'] = "-" + (options.width + 23) + "px";
						
						bubble = $("<div/>")
						.addClass("bubble")
						.css(bubble_css)
						.html(								
							$("<div/>")
							.append(
								$("<div/>")
								.css({
									'border-color': 'transparent rgba(0, 0, 0, 0.8) transparent transparent',
									'border-style': 'solid',
									'border-width': '5px',
									'width': 0,
									'height': 0,
									'margin': '8px 0 0 0',
									'float': 'left',
									'clear': 'left'
								})
							)
							.append(
								$('<div class="inner"></div>')
								.html(options.html)
								.css({
									'margin': '0 0 0 10px',
									'width': options.width + "px"
								})
							)
						)
						.appendTo(options.target)
						.fadeIn('fast');
						break;
						
					case 'left':
						bubble_css['top'] = "-4px";
						bubble_css['left'] = "-" + (options.width + 26) + "px";
					
						bubble = $("<div/>")
						.addClass("bubble")
						.css(bubble_css)
						.html(								
							$("<div/>")
							.append(
								$("<div/>")
								.css({
									'border-color': 'transparent transparent transparent rgba(0, 0, 0, 0.8)',
									'border-style': 'solid',
									'border-width': '5px',
									'width': 0,
									'height': 0,
									'margin': '8px 0 0 0',
									'float': 'right',
									'clear': 'right'
								})
							)
							.append(
								$('<div class="inner"></div>')
								.html(options.html)
								.css({
									'float': 'right',
									'width': options.width + "px"
								})
							)
						)
						.appendTo(options.target)
						.fadeIn('fast');
						break;
						
					default:	
						if (! bubble_css['bottom']) {						
							bubble_css['bottom'] = "-12px";
						}
						if (! bubble_css['left']) {
							bubble_css['left'] = "-" + (options.width - 26) + "px";
						}
						
						bubble = $("<div/>")
						.addClass("bubble")
						.css(bubble_css)
						.html(								
							$("<div/>")
							.append(
								$("<div/>")
								.css({
									'border-color': 'transparent transparent rgba(0, 0, 0, 0.8) transparent',
									'border-style': 'solid',
									'border-width': '5px',
									'width': '0',
									'height': '0',
									'margin': '0 10px 0 0'
								})
							)
							.append(
								$('<div class="inner"></div>')
								.html(options.html)
								.css("width", options.width + "px")
							)
						)
						.appendTo(options.target)
						.fadeIn('fast');
						break;
				}
			};
			
			init();
		}
	};
	
	rr.autocomplete = function(options) {
			
		var listening		= false;
		var last_val		= '';
		
		var container		= options.container;
		var input			= container.find('input');
		var list			= options.list || [];
		var ul				= $("<ul></ul>").addClass('autocomplete').appendTo(container);
		
		var max_results		= 5;
		
		var search = this.search = function(val) {
			var results = rr.tool.filter(list, val);
			var slice_count;
			
			if (results.length > max_results) {
				slice_count = results.length;
				results = results.slice(0, max_results);
			} else {
				slice_count = false;
			}
			
			if (results.length) {
				show_list(results, slice_count);
			} else {
				hide_list();
			}
		};
		
		var create = function() {					
			input.focus(start_listener);
			input.blur(stop_listener);
			input.keypress(function(e) {
				var code = e.keyCode || e.which;
				var input = $(this);
				
				if (code === rr.tool.key.ESCAPE) {
					stop_listener();
					hide_list();
				} else {
					start_listener();
				}
			});
		};
		
		var start_listener = function() {
			if (! listening) {
				listening = true;
				listen();
			}
		};
		
		var stop_listener = function() {
			listening = false;
			if (! input.val().length) {
				hide_list();
			}
		};
		
		var listen = function() {

			if (listening) {
				var val = input.val();
				
				if (! val.length) {
					hide_list();
				} else if (last_val !== val) {
					last_val = val;
					search(val);
				}
				
				setTimeout(listen, 100);
			}
		};
		
		var show_list = function(arr, original_count) {
			if (ul.html().length) {
				ul.html('');
			}
			input.addClass("focused");
			for (var i=0; i < arr.length; i++) {
				ul.append(create_item(arr[i]));
			}
			
			if (original_count > arr.length) {
				ul.append(create_other_item('<div class="additional">Showing ' + max_results + ' of ' + original_count + ' results</div>'));
			}
			ul.css('display', 'block');			
		};
		
		var hide_list = function() {
			input.removeClass("focused");
			ul.css('display', 'none');
		};
		
		var create_item = function(result) {		
			return $("<li></li>")
				//.data("id", result.id)
				.html('<a href="/member/view/' + result.id + '">' + result.name + '</a>')
				.append($("<div></div>").addClass("clear"))
				.prepend($("<img>").attr({
					src: result.picture,
					alt: ""
				}))
				.click(function(){
					location.href = '/member/view/' + result.id;
				})
				.appendTo(ul);
		};
		
		var create_other_item = function(body) {		
			return $("<li></li>")
				.html(body)
				//.click(function(){
				//	location.href = '/member/view/' + result.id;
				//})
				.appendTo(ul);
		};
				
		create();
	};
	
	
	$(document).ready(function(){
		$("img").error(function(){
			$(this).hide();
		});
	});

