$(
  function() {
    var User = new function() {
	  // private scope
	  var settings = {
		$body: $('body'),
	    url: $('#logo').attr('href'),
		validationError: 'These fields contain errors:',
		boxSelectors: { 
		  menu: {
		    $el: $('a.m', $('ul.submenu:eq(0)')),
			type: 'menu',
			html: '<div id="af_wrap" class="popout-box"><div class="w"></div></div>',
			width: 150,
			initialised: false,
			els : {},
			groups: [],
			maxlen: 0,
			reopen: true
		  },		
		  forgotPassword: {
		    $el: $('#forgot-password'),
			type: 'form',
			html: '<div id="af_wrap" class="popout-box"><div class="w"><form><div><label for="af_s" class="nofloat">Your Username</label><br /><input type="text" name="s" id="af_s" maxlength="16" size="20" class="field" /> <input type="submit" name="Operation" id="af_btn" value="Submit" class="btn" /></div></div></form></div>',
			width: 205,
			initialised: false,
			url: 'extensions/com/contacts/ContactAjaxGateway.cfc',
			method: 'sendPassword',
			els : {},
			validate: [ { id: 'af_s', re: /^[^\s]{4,16}$/ } ],
			json: null,
			reset: true,
			reopen: false,
			success: 'The password for you account has been sent to your email address.',
			fail: 'The username that you have entered could not be found, please ensure that you have entered your username correctly.'
		  },
		  checkUsername: {
		    $el: $('#check-username'),
			type: 'form',
			html: '<div id="af_wrap" class="popout-box"><div class="w"><form><div><label for="af_s" class="nofloat">Desired Username</label><br /><input type="text" name="s" id="af_s" maxlength="16" size="20" class="field" /> <input type="submit" name="Operation" id="af_btn" value="Check" class="btn" /></div></form></div></div>',
			width: 205,
			initialised: false,
			url: 'extensions/com/contacts/ContactAjaxGateway.cfc',
			method: 'loginAvailable',
			els : {},
			validate: [ { id: 'af_s', re: /^[^\s]{4,16}$/ } ],
			json: null,
			reset: false,
			reopen: false,			
			success: 'The username is available.',
			fail: 'The username is unavailable.'
		  },
		  features: {
		    $el: $('a.feature'),
			type: 'text',
			html: '<div id="af_wrap" class="popout-box"><div class="w"></div></div>',
			width: 400,
			initialised: false,
			url: 'extensions/com/features/FeatureAjaxGateway.cfc',
			method: 'get',
			els : {},
			json: null,
			success: 'Found.',
			fail: 'Not found.',
			reopen: true,			
			callback: function(s, JSON) { 
			  s.els.a.after(
				'<h1>' + JSON[0].feature_name + '</h1>' + '<p>' + (JSON[0].feature_description.length ? JSON[0].feature_description : 'No description found.') + '</p>' 
			  );
			}
		  }
		},
		subscriptions: {
		  $table: $('#choose-subscriptions'),
		  $form: $('#subscription-form'),
		  $paypal: $('#pp-btn'),
		  checkedClass: 'checked'
		}
	  };
	  var util = {
		loading : function(d, y) {
	      var $loading = $('#loading');

	      if (!$loading.length) {
	        $loading = $('#loading', $('body').append('<div id="loading"><div><img src="' + settings.url + 'public/images/working.gif" /> Working...</div></div>'));
	      }
	      if (d) {
	        $loading.children('div').css('top', y).end().fadeIn('fast');
	      } else {
	        $loading.fadeOut('fast');	  
	      }
	    },
	    getPosition : function(el) {
		  var x = 0, y = 0;
		  while(el) {
			x += el.offsetLeft || 0;
			y += el.offsetTop || 0;
			el = el.offsetParent;
		  }
		  return { x:x, y:y };
	    } 
	  };

	  var boxes = {
		init : function() {
		  $.each(
		    settings.boxSelectors,
		    function(i, n) {
			  var s = settings.boxSelectors[i];
		
		      switch (s.type) {
			    case 'menu': {
				  s.$el.each(
				    function(i) {
					  s.groups.push($('a[@rel="' + this.rel + '"]', s.$el.parents('ul.submenu:eq(0)')).not(this));    
					  s.groups[i].parents('li').hide();
				    }
				  );
				  break;
			    }
			    default: {
				  break;  
			    }
			  }

			  s.$el.bind(
			    'click',
			    function(e) {
				  boxes.build(s, e.target);
				  return false;
			    }
			  );
		    }
		  );
	    },
	    build : function(s, el) {
		  var pos = util.getPosition(el);
		  var $el = $(el);
		  var $w = $('#af_wrap');

		  if (s.initialised || $w.length) {
		    boxes.remove($w, s, el, s.reopen);
		    return;
		  } 

		  if (!s.initialised) {
		    settings.$body.append(s.html);
		  
		    s.el = el;
		    s.els.wrap = $('#af_wrap').prepend('<div class="a"></div>').hide().css({ position: 'absolute', left: pos.x, top: pos.y + 20, width: s.width });
		    s.els.wrapper = $('div.w', s.els.wrap);
		    s.els.p = $('p', s.els.wrapper.append('<p class="message"></p>')).css({ margin: '10px 0px 0px 0px' }).hide();
		    s.els.a = $('a', s.els.wrapper.prepend('<a href="javascript:;" class="c" title="Close">[X]</a>')).bind(
			  'click',
			  function(e) {
			    boxes.remove(s.els.wrap, s, el, false);
			    return false;
			  }
		    );
		  
		    switch (s.type) {
		      case 'form': {
			  
		  	    s.els.form = $('form', s.els.wrap).bind(
				  'submit',
				  function(e) {
				    if (boxes.validate(s)) {
					  util.loading(true, pos.y); 
					    
					  $.post(
					    settings.url + s.url,
					    'method=init&methodname=' + s.method + '&returntype=json&' + $.param(s.els.fields),
					    function(json) {
						  s.json = eval(json);
						  s.json ? boxes.message(s.success, s, true) : boxes.message(s.fail, s, true);
						
						  if (s.reset) {
						    s.els.form.get(0).reset();
						  }
						  boxes.focusIn(s);
						
						  util.loading(false);
					    }
					  );
				    }
				    return false;
				  }
			    );
			    s.els.fields = $('input,select,textarea', s.els.form);	
			  
			    break;
		      }
			  case 'text': {
			    util.loading(true, pos.y - 100); 

			    $.getJSON(
				  settings.url + s.url,
				  'method=init&methodname=' + s.method + '&returntype=json&id=' + $el.attr('rel'),
				  function(JSON) {
				    s.callback(s, JSON);
				  
				    util.loading(false);
				  }
			    );
			  
			    break;	
			  }
			  case 'menu': { 
				s.maxlen = 0;
			    s.groups[s.$el.index(el.parentNode)].each(
				  function(i) {
				    var t = this.firstChild.firstChild.nodeValue;
				    s.maxlen = t.length > s.maxlen ? t.length : s.maxlen;
				    s.els.wrapper.append('<a href="' + this.href + '" class="sm">' + t + '</a><br />');					  
			      }
			    );
			    s.els.wrap.width((s.maxlen * 6) + 30);
			  
			    break;
			  }
		    }

		    s.els.wrap.show(
		      'fast', 
		      function() {
			    boxes.focusIn(s);
		      }
		    );
		  
		    s.initialised = true;
		  }
		
		  boxes.message('', s, false);
	    },
	    remove : function($el, s, el, reopen) {
		  return (el == -1 || $(s.el).index(el) == -1) ? $el.hide(
		    'fast', 
		    function() {
			  $(this).remove();  				
			  s.initialised = false;   		
			  if (reopen) {
			    boxes.build(s, el);				  
			  }
		    }
		  ) : boxes.remove($el, s, -1, false); 
	    },
	  
	    validate : function(s) {
		  var m = settings.validationError;
		  var f = [];
		
		  $.each(
		    s.validate,
		    function(i, p) {
		      if (!p.re.test($('#' + p.id).val())) {
			    f.push($('label[@for="' + p.id + '"]', s.els.wrap).text());
			  }
		    }
		  );
		
		  if (f.length) {
		    boxes.message(m + '<br />' + f.join('<br />'), s, true);
		    boxes.focusIn(s);
		  } else {
		    boxes.message('', s, false);
		  }
		  return f.length ? false : true;
	    },
	    message : function(m, s, d) {
	      s.els.p.html(m);
		  d ? s.els.p.fadeIn(1500) : s.els.p.hide(); 
	    },
	    focusIn : function(s) {
	      try {
		    s.els.fields.get(0).focus(); 
		  } catch (e) {};
	    }
	  };
	  var subscriptions = {
		init : function() {
		  var s = settings.subscriptions;
		  if (s.$table.length) {
			subscriptions.enhance(s);
		  } else if (s.$paypal.length) {
			s.$paypal.attr('target', '_blank').bind(
			  'click',
			  function() {
				window.location = s.$form[0].action;   
			  }
			);
		  }
		},
		enhance : function(s) {
		  $('tbody > tr', s.$table).each(
			function (i) {
			  var $row = $(this);
			  var $radioCell = $('td:first', $row).bind(
				'click',
				function(e) {
				  subscriptions.check($(this), s);
				}
			  );
			  if ($('input', $radioCell).get(0).checked) {
				$radioCell.addClass(s.checkedClass);
			  }
			}
		  );
		},
		uncheck : function(s) {
		  $('tbody > tr', s.$table).each(
			function(i) { 
			  $('td:first', this).removeClass(s.checkedClass); 
			}
		  );
		},
		check : function($c, s) {
		  subscriptions.uncheck(s);			
		  $('input', $c.addClass(s.checkedClass)).attr('checked', 'checked');
		}
	  };
	  var other = {
		init : function() {
		  try {
		    $('input.picker').calendar({ speed: 'fast', buttonImage: settings.url + 'public/images/calendar.png', autoPopUp: 'button', buttonImageOnly: true, buttonText: '', dateFormat: $('input[@name=picker_format]').val() }); 			
		  } catch (e) {};
		}
	  };
	  
	  // public scope
	  this.init = function() {		  
	    boxes.init();
		subscriptions.init();
		other.init();
	  };	  
	};
	
	// init the user 
	User.init();
  }
);