
String.prototype.trim = function () { return this.replace(/^\s*/, "").replace(/\s*$/, ""); };

var Resource = {
	Checkin: {
		$input: {},
		$reflection_form: {},
		$submit_button: {},
		register: function($input, $reflection_form, $submit_button) {
			this.$input           = $input;
			this.$reflection_form = $reflection_form;
			this.$submit_button   = $submit_button;
			this.init($input);
		},
		init: function() {
			Resource.UI.Effects.disable(this.$submit_button);
			this.$input.focus(Resource.Checkin.focus).blur(Resource.Checkin.blur);
		},
		reset: function() {
			this.$input.unbind();
			Resource.Input.Tip.register(Resource.Checkin.$input, Resource.Checkin.$input.data('default'));
			Resource.Checkin.init();
		},
		/**
		 * @todo:	1) change CSS with classes
		 *			2) find a way of disabling elastic() without unbind()
		 */
		focus: function() {
			var $t = $(this);
			if (this.value == '' || $t.hasClass('default'))
			{
				var css = {
					'marginBottom': '4px',
					'minHeight':    '3.6em'
				};
				if ($t.parents('#feed').length)
				{
					css.width = '424px';
				}
				$t.bind('keyup', Resource.Checkin.keyup).css(css);
				Resource.Input.Elastic.register($t);
				$('.date', $t.parent()).show();
			}
		},
		blur: function() {
			var $t = $(this);
			if (this.value == '' || $t.hasClass('default'))
			{
				var css = {
					'marginBottom': '0',
					'height': '1.2em',
					'minHeight':    '0'
				};
				if ($t.parents('#feed').length)
				{
					css.width = '295px';
				}
				$t.unbind('keyup', Resource.Checkin.keyup).css(css);
				$('.date', $t.parent()).hide();
				Resource.Checkin.reset();
			}
		},
		keyup: function()
		{
			if (this.value == '')
			{
				Resource.Checkin.$reflection_form.slideUp('fast');
				Resource.UI.Effects.disable(Resource.Checkin.$submit_button);
			}
			else
			{
				if (Resource.Checkin.$reflection_form.is(':hidden'))
				{
					Resource.Checkin.$reflection_form.slideDown('fast', function() {
						$('textarea', Resource.Checkin.$reflection_form).animate({
							height: '3.2em'
						}, 'normal', function() {
							Resource.Input.Elastic.register($(this));
						});
					});
				}
				Resource.UI.Effects.enable(Resource.Checkin.$submit_button);
			}
		}
	},
	Date: {
		register: function($obj) {
			/* make sure the function is loaded */
			if ($.isFunction($.fn.datepicker))
			{
				var config = {
					showOn: "both",
					buttonImage: "public/images/icons/calendar.gif",
					buttonImageOnly: true
				};
				if ($obj.metadata().past_only)
				{
					config.maxDate = 0;
				}
				$obj.datepicker(config);
			}
			else
			{
				console.log('$.fn.datepicker is not a function! Did you load the jQuery UI libraries? (ICK!)')
			}
		}
	},
	Dialog: {
		open_dialogs: [],
		register: function($triggers)
		{
			$triggers.each(function() {
				var $t = $(this);
				var href = $t.attr('href');
				if (href.indexOf('?') == -1)
				{
					$t.attr('href', href+'?dialog=1');
				}
				else
				{
					$t.attr('href', href.replace('?', '?dialog=1&'));
				}
			}).click(function(e) {
				Resource.Dialog.load($(this).attr('href'));
				e.stopPropagation();
				return false;
			}).removeClass('dialog-trigger').addClass('dialog-init');
		},
		register_defaults: function() {
			this.register($('.dialog-trigger'));
		},
		load: function(url) {
			var $dialog = $('#dialog').clone().appendTo('#wrapper');
			$dialog.attr('id', '');
			var iframe = (url.indexOf('://')!==-1);
			$dialog.data('iframe', iframe).jqm({
				ajax: url,
				ajaxText: '<h3><img src="public/images/ajax-loader.gif" alt="" /> Loading...</h3>',
				onLoad: function(hash) {
					$(':input.focus:first', hash.w).select();
					$(hash.w).jqmAddClose('.dialog-close');
					Resource.Loader.init();
				},
				onHide: function(hash)
				{
					Resource.Dialog.close(hash.w.data('dialog_index'));
					hash.o.remove();
				},
				target: !iframe?'.jqmContent':'.jqmFrame'
			}).jqmShow();
			$dialog.data('dialog_index', this.open_dialogs.length);
			this.open_dialogs.push($dialog);
		},
		close: function() {
			var $dialog = this.open_dialogs.pop();
			$dialog.remove();
		}
	},
	Feed: {

	},
	Form: {
		reset: function($forms) {
			$forms.each(function() {
				this.reset();
			});
		}
	},
	Input: {
		Cursor: {
			get: function(el) {
				// non-IE
				if (el.selectionStart)
				{
					return el.selectionStart;
				}
				// IE
				else if (document.selection)
				{
					el.focus();
					var r = document.selection.createRange();
					if (r == null)
					{
						return 0;
					}
					var re = el.createTextRange(),
					rc = re.duplicate();
					re.moveToBookmark(r.getBookmark());
					rc.setEndPoint('EndToStart', re); 
					return rc.text.length;
				}
				return 0;


			},
			set: function(el,st,end) {
				// non-IE
				if(el.setSelectionRange)
				{
					el.focus();
					el.setSelectionRange(st,end);
				}
				// IE
				else
				{
					if(el.createTextRange)
					{
						range=el.createTextRange();
						range.collapse(true);
						range.moveEnd('character',end);
						range.moveStart('character',st);
						range.select();
					}
				}
			},
			disable: function(el) {
				el.each(function() {
					if (typeof this.onselectstart != "undefined") //IE route
					{
						console.log('disable selection: IE');
						this.onselectstart = function(){ return false };
					}
					else if (typeof this.style.MozUserSelect != "undefined") //Firefox route
					{
						console.log('disable selection: FF');
						this.style.MozUserSelect = "none";
					}
					else //All other route (ie: Opera)
					{
						console.log('disable selection: other');
						this.onmousedown = function() { return false };
						this.style.cursor = "default"
					}
				});
			}
		},
		Elastic: {
			register: function($el) {
				if ($.isFunction($.fn.elastic))
				{
					$el.elastic();
				}
				else
				{
					console.log('$.fn.elastic is not a function! Did you load jquery.elastic.js?')
				}
			}
		},
		Limit: {
			register: function($el) {
				$el.focus(Resource.Input.Limit.focus);
			},
			focus: function() {
				var $t = $(this);
				$t.bind('blur', Resource.Input.Limit.blur)
				  .bind('keyup', Resource.Input.Limit.keyup);
			},
			blur: function() {
				$(this).unbind('blur', Resource.Input.Limit.blur)
					   .unbind('keyup', Resource.Input.Limit.keyup);
			},
			keyup: function() {
				var $t = $(this);
				if ($t.val().length > $t.metadata().limit)
				{
					// limit value (and restore cursor position)
					var pos = Resource.Input.Cursor.get(this);
					$t.val($t.val().substring(0, $t.metadata().limit));
					Resource.Input.Cursor.set(this, pos, pos);
				}
			}

		},
		Tip: {
			register: function($inputs, tips) {
				if ( !$.isArray(tips))
				{
					tips = new Array(tips);
				}
				if ($inputs.length != tips.length)
				{
					console.log('inputs length does not match tooltips length!');
					return false;
				}
				$inputs.each(function(i) {
					var $input = $(this);
					$input.data('default', tips[i]);
					if ($input.val() == '' || $input.hasClass('default'))
					{
						$input.addClass('default').val(tips[i]);
						if ( !$input.hasClass('default-init'))
						{
							$input.bind('focus', Resource.Input.Tip.focus);
						}
					}
				}).addClass('default-init');
				return $inputs;
			},
			register_defaults: function() {
				var $inputs = $('.default:not(.default-init');
				var tooltips = [];
				$inputs.each(function() {
					tooltips.push(this.value);
					this.value = '';
				});
				this.register($inputs, tooltips);
			},
			focus: function() {
				var $t = $(this).bind('blur',    Resource.Input.Tip.blur)
								.bind('keyup',   Resource.Input.Tip.keyup)
								.unbind('focus', Resource.Input.Tip.focus);
				if ($t.hasClass('default'))
				{
					$t.val('').removeClass('default').addClass('had-default');
				}
			},
			blur: function() {
				var $t = $(this).unbind('blur',  Resource.Input.Tip.blur)
								.unbind('keyup', Resource.Input.Tip.keyup)
								.bind('focus',   Resource.Input.Tip.focus);
				if ($t.val() == '')
				{
					Resource.Input.Tip.revert($t);
				}
			},
			revert: function($t) {
				$t.val($t.data('default')).addClass('default').removeClass('had-default').parent().removeClass('has-value');
			},
			keyup: function() {
				$(this).parent().toggleClass('has-value', (this.value.trim() != ''));
			}
		}
	},
	Relationships: {
		init_follow: function() {
			$('.stop_following, .follow').not('.follow-init').click(function(e) {
				$t = $(this);
				var opts = {};
				if ($t.hasClass('follow'))
				{
					opts.action   = 'follow';
					opts.disabled = null;
					if (!$t.hasClass('nostop'))
					{
						opts.next_action = 'stop_following';
						opts.next_label  = 'Stop Following';
					}
					else
					{
						opts.next_action = '';
						opts.next_label  = 'Following';
						opts.disabled    = 'disabled';
					}
				}
				else if ($t.hasClass('stop_following'))
				{
					opts.action      = 'stop_following';
					opts.disabled    = null;
					opts.next_action = 'follow';
					opts.next_label  = 'Follow';
				}

				opts.user = $t.attr('id').split('_')[1];
				$t.attr('disabled', 'disabled').addClass('btn-disabled').html('Please Wait...');
				$.getJSON('/ajax/'+opts.action+'_person/'+opts.user, {}, function(data) {
					if (data == null || data.rsp != 'ok')
					{
						$t.replaceWith('<span class="error">Failed!</span"');
					}
					else
					{
						$t.fadeOut('fast', function() {
							if (opts.disabled != 'disabled')
							{
								$t.removeClass('btn-disabled');
							}
							$t.removeClass(opts.action)
								.addClass(opts.next_action)
								.html(opts.next_label)
								.attr('disabled', opts.disabled)
								.fadeIn('fast');
							});
						if (opts.action == 'stop_following')
						{
							$('.only-following #following_'+opts.user).fadeOut('fast', function() { $(this).remove(); });
						}
						if (typeof data.translate != 'undefined')
						{
							Resource.UI.Content.translate(data.translate);
						}
					}
				});
				e.stopPropagation();
				return false;
			}).addClass('follow-init');
		},
		init_like: function() {
			$('.stop_liking, .like').click(function(e) {
				$t = $(this);
				var opts = {};
				if ($t.hasClass('like'))
				{
					opts.action   = 'like';
					opts.disabled = null;
					if (!$t.hasClass('nostop'))
					{
						opts.next_action = 'stop_liking';
						opts.next_label  = 'Stop Liking';
					}
					else
					{
						opts.next_action = '';
						opts.next_label  = 'Liking';
						opts.disabled    = 'disabled';
					}
				}
				else if ($t.hasClass('stop_liking'))
				{
					opts.action      = 'stop_liking';
					opts.disabled    = null;
					opts.next_action = 'like';
					opts.next_label  = 'Like';
				}

				opts.organizer = $t.attr('id').split('_')[1];
				$t.attr('disabled', 'disabled').addClass('btn-disabled').html('Please Wait...');
				$.getJSON('/ajax/'+opts.action+'_organizer/'+opts.organizer, {}, function(data) {
					if (data == null || data.rsp != 'ok')
					{
						$t.replaceWith('<span class="error">Failed!</span"');
					}
					else
					{
						$t.fadeOut('fast', function() {
							if (opts.disabled != 'disabled')
							{
								$t.removeClass('btn-disabled');
							}
							$t.removeClass(opts.action)
								.addClass(opts.next_action)
								.html(opts.next_label)
								.attr('disabled', opts.disabled)
								.fadeIn('fast');
							});
						if (opts.action == 'stop_liking')
						{
							$('.only-liking #liking_'+opts.user).fadeOut('fast', function() { $(this).remove(); });
						}
						if (typeof data.translate != 'undefined')
						{
							Resource.UI.Content.translate(data.translate);
						}
					}
				});
				e.stopPropagation();
				return false;
			});
		},
		nudge: function(el, invite_id) {
			var $t = $(el);
			Resource.UI.Effects.disable($t.html('Nudging...'));
			$.post('/ajax/nudge/'+invite_id, {}, function() {
				$t.html('Nudged!');
			});
		}
	},
	Searchwidget: {
		timer: null,
		results: [],
		init: function() {
			$('.search-widget').each(function() {
				var $t = $(this);
				if ($t.metadata().multiple)
				{
					var hidden = $('.result', $t).length ? '' : 'hidden ';
					$('<a href="javascript:{}" class="'+hidden+'add-another-trigger" onclick="Resource.Searchwidget.add_search_box($(this).prev())">Add Another</a>').insertAfter($t);
				}
				var $inputs  = $([]);
				var tooltips = [];
				var tooltip  = 'Start typing '+$t.metadata().type+'\'s name...';
				$('input:not(.init)', this).each(function() {
					$inputs.push(this);
					tooltips.push(tooltip);
					var $t = $(this);
					$t.blur(function() {
						var $t = $(this);
						setTimeout(function() {
							var $ul = $('ul', $t.parent());
							var first_result = $('li a:first', $ul)
							if (first_result.length)
							{
								first_result.trigger('click');
							}
							$ul.fadeOut('fast', function() { $(this).remove(); });
						}, 500);
					}).keyup(function() {
						clearTimeout(Resource.Searchwidget.timer);
						var $t = $(this);
						var q = $t.val().replace(/[^a-zA-Z0-9\- \.\,]/, '');
						if (q != '')
						{
							Resource.Searchwidget.timer = setTimeout(function() {
								var $p = $t.parents('.search-widget');
								var path = 'ajax/search/widget/'+$p.metadata().type;
								var data = $p.metadata();
								data.q = q;
								if ($p.metadata().multiple)
								{
									var exclude = [];
									$('input:hidden', $p).each(function() {
										exclude.push(this.value);
									});
									data.exclude = exclude.join(',');
								}
								$.get(path, data, function(data) {
									Resource.Searchwidget.result_list(data, $t.parent());
								});
							}, 500);
						}
					}).addClass('init').trigger('blur');
				});
				Resource.Input.Tip.register($inputs, tooltips);
			});
		},
		add_search_box: function(el) {
			var $div = $('div.search-widget-container:last', el).clone(true).appendTo(el);
			$('.result, a', $div).remove();
			$('input.text', $div).val('').trigger('blur').show().focus().after(' &nbsp; <a href="javascript:void(0)" onclick="Resource.Searchwidget.remove_result(this)">remove</a>');
			el.next().hide();
		},
		result_list: function(data, target) {
			if (data != this.results)
			{
				this.results = data;
				var $ul = $('<ul />');
				if (data != '{}')
				{
					data = eval('('+data+')');
					for (var i in data)
					{
						$ul.append('<li><a href="javascript:void(0)" onclick="Resource.Searchwidget.select_result('+i+', this)"><img src="'+data[i].image+'/thumb" alt="" />'+data[i].name+'</a></li>')
					}
				}
				else
				{
					$ul.append('<li class="disabled padded"><em>No Results. Try something else.</em></li>');
				}
				$('ul', target).remove();
				$ul.appendTo(target);
			}
		},
		select_result: function(id, el) {
			el = $(el);
			var $p = el.parents('div:first');
			$('input.text', $p).val(id).hide().after('<span class="result">'+el.html()+' &nbsp; <a href="javascript:void(0)" onclick="Resource.Searchwidget.edit_result(this)">edit</a></span>');
			var $widget = el.parents('.search-widget');
			if ($widget.metadata().multiple)
			{
				Resource.Searchwidget.add_search_box($widget);
			}
			$('ul', $p).remove();
			if ($widget.metadata().add_cb)
			{
				$widget.metadata().add_cb();
			}
		},
		remove_result: function(el) {
			el = $(el);
			$widget = el.parents('.search-widget');
			el.parents('.search-widget-container').remove();
			if ( !$('input.text:visible', $widget).length)
			{
				$widget.next().fadeIn('fast');
			}
			if ($widget.metadata().remove_cb)
			{
				$widget.metadata().remove_cb($('.result', $widget).length);
			}
		},
		edit_result: function(el) {
			el = $(el);
			$('input.text', el.parents('.search-widget-container')).val('').trigger('blur').show().focus();
			var $widget = el.parents('.search-widget');
			el.parents('.result').remove();
			if ($('.search-widget-container', $widget).length == 1)
			{
				$('a.add-another-trigger', $widget).fadeOut('fast');
			}
			if ($widget.metadata().remove_cb)
			{
				$widget.metadata().remove_cb($('.result', $widget).length);
			}
		}

	},
	Subsearch: {
		previous_query: '',
		_timer: null,
		init: function()
		{
			$('.subsearch-field input.search').keyup(this.do_search);
			$('form.subsearch .close-button').click(this.revert);
		},
		do_search: function() {
			var $t = $(this);
			var q  = $t.val();
			if (q.length >= 3 && q != Resource.Subsearch.previous_query)
			{
				$('#subsearch_results').html('<img src="/public/images/ajax-loader.gif" /> Loading...');
				clearTimeout(Resource.Subsearch._timer);
				Resource.Subsearch._timer = setTimeout(function() {
					$.get($t.parents('form').attr('action'), {q:q}, function(html) {
						$('#subsearch_orig_list').hide();
						$('#subsearch_results').html(html).slideDown('fast');
					});
				}, 250);
				Resource.Subsearch.previous_query = q;
			}
			else if (q.trim() == '')
			{
				Resource.Subsearch.revert();
			}
		},
		revert: function() {
			$('.subsearch-field input.search').get(0).select();
			$('#subsearch_results, #subsearch_orig_list').toggle();
			Resource.Subsearch.previous_query = '';
		}
	},
	UI: {
		init: function() {
			this.Effects.init();
			this.More.register_defaults();
			this.Toggle.register_defaults();
		},
		Effects: {
			init: function() {
				/* hover effect for list items */
				$('.list-item:not(ui-effects-init').hover(function() {
					$(this).addClass('hover');
				}, function() {
					$(this).removeClass('hover');
				}).addClass('ui-effects-init');

				/* green status message */
				$('.message:visible').fadeTo('fast', .5).hover(function() {
					$(this).fadeTo('fast', 1);
				}, function() {
					$(this).fadeTo('fast', .5);
				});
			},
			disable: function($el)
			{
				$el.each(function() {
					var $t = $(this);
					if ($t.is('button'))
					{
						$t.addClass('btn-disabled').attr('disabled', 'disabled');
					}
					else if ($t.is('a.btn'))
					{
						$t.addClass('btn-disabled');
					}
					else
					{
						$t.addClass('disabled').attr('disabled', 'disabled');
					}
				});
				$el.bind('click', this._event_override);
			},
			_event_override: function(e)
			{
				e.stopImmediatePropagation();
				return false;
			},
			enable: function($el)
			{
				$el.each(function() {
					var $t = $(this);
					if ($t.is('button'))
					{
						$t.removeClass('btn-disabled').attr('disabled', '');
					}
					else if ($t.is('a.btn'))
					{
						$t.removeClass('btn-disabled');
					}
					else
					{
						$t.attr('disabled', '').removeClass('disabled');
					}
				});
				$el.unbind('click', this._event_override);
			}
		},
		Content: {
			translate: function(t) {
				var el;
				for(var i in t)
				{
					if (i == 'hide')
					{
						for (h in t[i])
						{
							$('.'+t[i][h]).fadeOut('slow');
						}
					}
					else
					{
						el = $('.'+i);
						if (el.html() != t[i])
						{
							el.hide().html(t[i]).fadeIn('fast');
						}
					}
				}
			}
		},
		More: {
			register: function(el)
			{
				el.click(function(e) {
					var $t  = $(this);
					var $m  = $t.metadata();
					var $ta = $($m.target);

					if ($ta.is(':visible'))
					{
						$ta.slideUp('fast');
						$t.text($m.more);
					}
					else
					{
						$ta.slideDown('fast');
						$t.text($m.less);
					}

					e.stopPropagation();
					return false;
				}).addClass('more-trigger-init');
			},
			register_defaults: function() {
				this.register($('.more-trigger:not(.more-trigger-init)'));
			}
		},
		Toggle: {
			register: function(el) {
				el.click(function() {
					$($(this).metadata().targets).slideToggle('fast');
				}).addClass('toggle-trigger-init');
			},
			register_defaults: function()
			{
				this.register($('.toggle-trigger:not(.toggle-trigger-init)'));
			}
		},
		Menu: {
			register: function($el) {
				$el.mousedown(function(e) {
					var $t = $(this);
					if ( !$t.hasClass('clicked'))
					{
						var $menu = $($t.metadata().menu);
						if ($menu.is(':hidden'))
						{
							Resource.UI.Menu.hide_visible();
							$t.addClass('clicked');
							$menu.fadeIn('fast');
							$(document).bind('mousedown', Resource.UI.Menu.hide_visible);
						}
						else
						{
							Resource.UI.Menu.hide_visible();
						}
						e.stopPropagation();
					}
				}).removeClass('menu-trigger');
			},
			hide_visible: function() {
				$('.clicked').removeClass('clicked');
				$('.menu:visible').fadeOut('fast');
				$(document).unbind('mousedown', Resource.UI.Menu.hide_visible);
			},
			register_defaults: function() {
				Resource.UI.Menu.register($('.menu-trigger'));
			}
		}
	},
	Suggestion: {
		accept: function(id)
		{
			$('#suggestion_'+id).slideUp('slow', function() {
				$(this).remove();
			});
			$.post('/ajax/suggestion/accept/'+id, {exclude:this._get_exclude()}, function(new_suggestion) {
				$(new_suggestion).hide().appendTo($('#suggestions')).fadeIn('slow');
			});
		},
		decline: function(id)
		{
			$('#suggestion_'+id).slideUp('slow', function() {
				$(this).remove();
			});
			$.post('/ajax/suggestion/decline/'+id, {exclude:this._get_exclude()}, function(new_suggestion) {
				$(new_suggestion).hide().appendTo($('#suggestions')).fadeIn('slow');
			});
		},
		_get_exclude: function() {
			var exclude = [];
			$('#suggestions li').each(function() {
				exclude.push($(this).attr('id').split('_')[1]);
			});
			return exclude;
		}
	},
	Loader: {
		hooks: [],
		register_hook: function(cb) {
			this.hooks.push(cb);
		},
		execute_hooks: function() {
			for (var i=0; i<this.hooks.length; i++)
			{
				this.hooks[i].call();
			}
		},
		init: function() {
			Resource.Dialog.register_defaults();
			Resource.Input.Tip.register_defaults();
			Resource.Relationships.init_follow();
			Resource.Relationships.init_like();
			Resource.UI.init();
			this.execute_hooks();
		}
	}
};

/* legacy functions */

var init_hooks = [];
function register_init_hook(cb)
{
	console.log('registering init hook...');
	console.log(cb.toString());
	Resource.Loader.register_hook(cb);
}

function init_content($rel)
{
	console.log('legacy init content...');
	console.log($rel);
	Resource.Loader.init();
}

function show_dialog(url)
{
	console.log('legacy show_dialog...');
	Resource.Dialog.load(url);
}

function hide_dialog()
{
	console.log('legacy hide_dialog. use the .dialog-close handler instead!');
}

function translate(t)
{
	console.log('legacy translate');
	Resource.UI.Content.translate(t);
}

/* Begin */
if (typeof console == 'undefined')
{
	var console = {
		log: function() { }
	};
}
$(function() {
	Resource.Loader.init();
});
