// DON'T I18N

//allocate namespaces
var bebo = {};
bebo.util = {};
bebo.ui = {};

// --jan-felix 
// See in JavascriptResource, e.g. LOCALS_GENERAL
if (typeof $I == 'undefined') {
  $I = {
	// very simple translator methods
	_getNamespaceByLocation: function() {
	  	var path = self.location.pathname.split('/');
		if (path.length>=2 && path[1]=='c' && path[2]) { 
			var namespace =  path[2].replace(/([a-z])([A-Z])/g,'$1_$2').toLowerCase();
			$I._getNamespaceByLocation = function() { return namespace; };
			return namespace;
		}
  	},
	_transfWithArgs: function(/*String*/ string, /*Object*/ transArgs , /*String?*/ namespace) {
		var replacer = function(string) {
	  		$each(transArgs||{}, function(replacement, placeholder){
	  			string = string.split('[:'+placeholder+']').join(replacement);
			});
	  		return string;
	  	};
	  	return replacer($I._transfWithoutArgs(string, namespace));
	},
	_transfWithoutArgs: function(/*String*/ string, /*String?*/ namespace) {
		namespace = namespace || 'general';
		var alternative = $I._getNamespaceByLocation();
		return (typeof I18NLocals=='object') && 
			$pick(I18NLocals[namespace] && I18NLocals[namespace][string], I18NLocals[alternative] && I18NLocals[alternative][string], string) || 
			string;
	},
	transf: function(/*String*/ string /*... transArgs, namespace */) {
		return (arguments.length>1 && typeof arguments[1] == 'object' && $I._transfWithArgs.apply(this, arguments)) || 
			$I._transfWithoutArgs.apply(this, arguments);
	}
  };
}


// moo tools should have $E but doesnt seem to be included in moo 1.2
if (typeof $E == 'undefined') {
	$E = function(selector, filter) {
		return ($(filter) || document).getElement(selector);
	};
}

if (typeof $ES == 'undefined') {
   $ES = function(selector, filter) {
      return ($(filter) || document).getElements(selector);
   };
}

// write back to DynamicValues from javascript
function $SV(value) {
	var path = [ 'DynamicValues' ];
	$A(arguments).each( function(item, index) {
		if (index > 0) {
			path.include(item);
		}
	});

	var evalPath = '';
	path.each( function(item, index) {
		evalPath += (index !== 0 ? '.' : '') + item;
		var lastItem = (index == path.length - 1);
		if (lastItem) {
			// console.log('setting: '+ evalPath +'='+ value);
			// todo: check for type
			eval(evalPath + "=\'" + value + "\'");
		} else {
			if (eval(evalPath) === undefined) {
				// console.log('creating: '+ evalPath);
				eval(evalPath + ' = $H()');
			}
		}
	});
}

// pull values from DynamicValues generated by java
function $V() {
	var path = "DynamicValues";
	$A(arguments).each( function(item, index) {
		path += "." + item;
	});
	try {
		return eval(path);
	} catch (err) {
		return null;
	}
}

/*
Script: dbug.js
   A wrapper for Firebug console.* statements.

License:
   http://clientside.cnet.com/wiki/cnet-libraries#license
*/
var dbug = {
   logged: [], 
   timers: {},
   firebug: false, 
   enabled: false, 
   log: function() {
      dbug.logged.push(arguments);
   },
   nolog: function(msg) {
      dbug.logged.push(arguments);
   },
   time: function(name){
      dbug.timers[name] = new Date().getTime();
   },
   timeEnd: function(name){
      if (dbug.timers[name]) {
         var end = new Date().getTime() - dbug.timers[name];
         dbug.timers[name] = false;
         dbug.log('%s: %s', name, end);
      } else { dbug.log('no such timer: %s', name); }
   },
   enable: function(silent) { 
      if(dbug.firebug) {
         try {
            dbug.enabled = true;
            dbug.log = function(){
                  (console.debug || console.log).apply(console, arguments);
            };
            dbug.time = function(){
               console.time.apply(console, arguments);
            };
            dbug.timeEnd = function(){
               console.timeEnd.apply(console, arguments);
            };
            if(!silent) {dbug.log('enabling dbug'); }
            for(var i=0;i<dbug.logged.length;i++){ dbug.log.apply(console, dbug.logged[i]); }
            dbug.logged=[];
         } catch(e) {
            dbug.enable.delay(400);
         }
      }
   },
   disable: function(){ 
      if(dbug.firebug) { dbug.enabled = false; }
      dbug.log = dbug.nolog;
      dbug.time = function(){};
      dbug.timeEnd = function(){};
   },
   cookie: function(set){
      var value = document.cookie.match('(?:^|;)\\s*jsdebug=([^;]*)');
      var debugCookie = value ? unescape(value[1]) : false;
      if((!$defined(set) && debugCookie != 'true') || ($defined(set) && set)) {
         dbug.enable();
         dbug.log('setting debugging cookie');
         var date = new Date();
         date.setTime(date.getTime()+(24*60*60*1000));
         document.cookie = 'jsdebug=true;expires='+date.toGMTString()+';path=/;';
      } else { dbug.disableCookie(); }
   },
   disableCookie: function(){
      dbug.log('disabling debugging cookie');
      document.cookie = 'jsdebug=false;path=/;';
   }
};

(function(){
	var fb = typeof console != "undefined";
	var debugMethods = ['debug','info','warn','error','assert','dir','dirxml'];
	var otherMethods = ['trace','group','groupEnd','profile','profileEnd','count'];
	function set(methodList, defaultFunction) {
		for(var i = 0; i < methodList.length; i++){
			dbug[methodList[i]] = (fb && console[methodList[i]])?console[methodList[i]]:defaultFunction;
		}
	}
	set(debugMethods, dbug.log);
	set(otherMethods, function(){});
})();
if (typeof console != "undefined" && console.warn){
	dbug.firebug = true;
	var value = document.cookie.match('(?:^|;)\\s*jsdebug=([^;]*)');
	var debugCookie = value ? unescape(value[1]) : false;
	if(window.location.href.indexOf("jsdebug=true")>0 || debugCookie=='true') { dbug.enable(); }
	if(debugCookie=='true') { dbug.log('debugging cookie enabled'); }
	if(window.location.href.indexOf("jsdebugCookie=true")>0){
		dbug.cookie();
		if(!dbug.enabled) { dbug.enable(); }
	}
	if(window.location.href.indexOf("jsdebugCookie=false")>0) { dbug.disableCookie(); }
}


Request.Partial = new Class({

   Extends: Request,

   options: {
      evalScripts: false,
      filter: false,
      replace: false,
      replaceTransition: function(oldElement, newElement) {
         newElement.replaces(oldElement);
      }
   },

   initialize: function(options){
      this.parent(options);
      this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
   },
   
   processHTML: function(text){
      var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
      text = (match) ? match[1] : text;

      var container = new Element('div');
      return container.set('html', text);
   },

   success: function(text){
      var options = this.options, response = this.response;
      
      response.json = JSON.decode(text, this.options.secure);
      
      response.html = response.json.data.html.stripScripts(function(script){
         response.javascript = script;
      });

      //temp is used if more than one element is returned in json 
      var temp = this.processHTML(response.html);
      var children = temp.getChildren();
      var el = children.length>1?temp:children[0];
      
      if (options.update) {
        $(options.update).empty().set('html', response.html);
      }
      if (options.replace) {
         options.replaceTransition(options.replace, el);
      }
      if (options.evalScripts) {
         $exec(response.javascript);
      }

      this.onSuccess(this.response.json, el, text);
   }
});



/**
 * Utility function which delays 'endofbody' to 'domready' for IE users
 */
bebo.util.fireEob = function() {
	var eob = function() {
		$(document).fireEvent('endofbody');
	};

	if (Browser.Engine.trident) {
		$(document).addEvent('domready', eob);
	} else {
		eob();
	}
};

/** Support for two new events on the window, windowenter and windowleave. These have been tested in 
 *  IE 6 and 7, FF 3, and Opera 9. Safari 3+ won't detect the user switching tabs.
 */
bebo.util.WindowEvents = new Class({
	initialize: function(){
		this.eventsPending = 0;
		this.lastEvent = '';
		this.enabled = true;
		this.eventToIgnore = '';
	},
	
	fireEvent: function(event){
		/**
		 * IE doubles up its events so you have a focusout right before a focusin. Similarly, 
		 * you can have several focusin events triggered when navigating the document. Checking to see
		 * if the event was the same as the last clears up the latter, and delaying event execution and checking 
		 * the number of events delays the former. All other browsers (say it with me) just work.
		 */
		if (event != this.lastEvent && this.eventsPending == 1 && this.enabled ){
			this.lastEvent = event;
			$(window).fireEvent(event);
		}
		this.eventsPending--;
	},
	
	iframeEntered: function(){
		this.enabled = false;
	},
	
	iframeLeft: function(event){
		this.enabled = true;
	},
	
	entered: function(){
		this.eventsPending++;
		this.fireEvent.delay(50,this,'windowentered');
	},
	
	left: function(){
		this.eventsPending++;
		this.fireEvent.delay(50,this,'windowleft');
	}
});

bebo.util.windowEvents = new bebo.util.WindowEvents();

if ( Browser.Engine.trident){
	document.onfocusin = bebo.util.windowEvents.entered.bind(bebo.util.windowEvents);
	document.onfocusout = bebo.util.windowEvents.left.bind(bebo.util.windowEvents);
} else if ( Browser.Engine.webkit ){
	// bind to the window for safari, the document doesn't register focus and blur
	$(window).addEvent('focus',bebo.util.windowEvents.entered.bind(bebo.util.windowEvents));
	$(window).addEvent('blur', bebo.util.windowEvents.left.bind(bebo.util.windowEvents));
} else {
	$(document).addEvent('focus',bebo.util.windowEvents.entered.bind(bebo.util.windowEvents));
	$(document).addEvent('blur', bebo.util.windowEvents.left.bind(bebo.util.windowEvents));
}

bebo.ui.registerIframeListeners = function(){
// provides iframe support where we suppress window events when entering and 
// leaving iframes
	$$('iframe-surround').each(function(elem,idx){
		$(elem).addEvent('mouseover',bebo.util.windowEvents.iframeEntered.bind(bebo.util.windowEvents));
		$(elem).addEvent('mouseout',bebo.util.windowEvents.iframeLeft.bind(bebo.util.windowEvents));
	});
};

// register iframe handler
$(document).addEvent('domready',bebo.ui.registerIframeListeners.bind(bebo.util.windowEvents));

/**
 * Input swaps between <input/>/<textarea> and a
 * <p>
 */
bebo.ui.HidingInput = new Class( {
	Implements : [ Options, Events ],

	options : {
		startingState :'input', // values: 'input', 'text'
		showText : function() {
			return true;
		}
	},

	/**
	 * el: input/textarea element to be used
	 */
	initialize : function(el, options) {
		this.element = $(el);
		this.setOptions(options);

		this.adopt();

		if (this.options.startingState == 'text') {
			this.swap();
		}
	},

	adopt : function() {
		this.element.addEvent('blur', this.swap.bindWithEvent(this));

		this.text = new Element('div', {
			'styles' : {
				'display' :'none'
			}
		});
		this.text.inject(this.element, 'after');
		this.text.addEvent('click', this.swap.bindWithEvent(this));

		// todo: match up sizing and what not
	},

	swap : function() {
		if (this.element.getStyle('display') == 'block' && 
				this.options.showText()) {
			this.element.setStyle('display', 'none');
			this.text.setStyle('display', 'block');

			var val = this.element.get('value');
			var test = val.replace(/\n/g, '<br/>');

			this.text.set('html', test);
		} else if (this.element.getStyle('display') != 'block') {
			this.text.setStyle('display', 'none');
			this.element.setStyle('display', 'block');
			$(this.element).selectRange(0, this.element.get('value').length);
			this.fireEvent('input', this.element);
		}
	}
});

/**
 * Convert a
 * <ul>
 * into a drop down
 */
bebo.ui.DropDown = new Class( {
   Implements : [ Options, Events ],

   options : {
      zIndex :200,
      hideDelay: 250
   },

   initialize : function(element, options) {
      this.setOptions(options);
      this.element = $(element);
      if (!this.element) {
         return;
      }

      this.title = this.element.getElement('li'); // first li node
      this.dropdown = this.title.getNext(); // should always be a 'ul'
      this.boundMouseLeave = this.mouseLeave.bindWithEvent(this);

      this.attach();
   },

   attach : function() {
      // make sure this.element has a defined position so that the drop downs
      // absolute position will work properly
      var style = this.element.getStyle('position');
      if (!$defined(style) || style == 'static') {
         this.element.setStyle('position', 'relative');
      }

      if (!this.dropdown) {
         return;
      }

      this.dropdown.set('styles', {
         'display' :'none',
         'position' :'absolute',
         'top' :this.title.getSize().y - 1,
         'z-index' :this.options.zIndex
      });

      this.title.addEvent('click', this.titleClick.bindWithEvent(this));
      this.element.addEvent('mouseover', function(){ 
         //mouse over fires as you trasition between children of this.element
         this.over=true;
      }.bind(this));
   },

   titleClick : function(event) {
      event.preventDefault();
      if (this.element.hasClass('active')) {
         this.hide();
      } else {
         this.over = true;
         this.element.addClass('active');
         this.dropdown.setStyles({'display': 'block', 'opacity': 1});
         this.element.addEvent('mouseleave', this.boundMouseLeave);
      }
   },

   mouseLeave : function(event) {
      this.over = false;
      this.hide.delay(this.options.hideDelay, this);
   },

   hide : function() {
      if(this.over) { return; }
      
      this.element.removeClass('active');
      this.dropdown.fade('out');

      this.element.removeEvent('mouseleave', this.boundMouseLeave);
   }
});

/**
 * Allows you to specify a message in the input fields value or innerText which
 * will auto hide on focus
 */
bebo.ui.InputMessage = new Class( {
	Implements :Options,

	property :'value', // we may want to support other properties in the future

	initialize : function(el, options) {
		this.element = $(el);
		this.setOptions(options);

		if (this.options.message) {
			this.element.set(this.property, message);
		}

		this.text = this.getValue();
		this.element.addEvent('focus', this.focus.bindWithEvent(this));
		this.element.addEvent('blur', this.blur.bindWithEvent(this));
	},

	getValue : function() {
		return this.element.get(this.property);
	},

	focus : function() {
		if (this.element.get(this.property) == this.text) {
			this.element.set(this.property, '');
		}
	},

	blur : function() {
		if (this.element.get(this.property) === '') {
			this.element.set(this.property, this.text);
		}
	}
});

bebo.ui.ExpandingTextArea = new Class( {
	Implements : [ Options, Events ],

	options : {
	// todo: maxHeight/maxRows
	},

	initialize : function(element, options) {
		this.setOptions(options);
		this.element = $(element);

		this.startingRows = this.element.get('rows');
		this.element.addEvent('keyup', this.keyUp.bindWithEvent(this));
		this.keyUp( {}); // there might already be text in the field
	},

	keyUp : function(event) {
		var e = this.element;

		if (event.key == 'backspace') {
			while (e.rows > this.startingRows && 
					e.getScrollSize().y < e.getSize().y) {
				e.rows--;
			}
		} else {
			while (e.getScrollSize().y > e.getSize().y) {
				e.rows++;
			}
		}
	}
});

bebo.ui.PhotoSelector2 = new Class({
	Implements : [ Options, Events ],

	options : {
		baseUrl :'/c/photo_selector/',
		selected : [],
		display :'popup', // values: 'popup', 'inline'
		select : 'many' // values: 'many', 'one'
	},

	initialize : function(options) {
	   this.options.memberId = $V('Member', 'id');
		this.setOptions(options);

		this.adopt();
	},

	adopt : function() {
	   var opt = this.options;
	   
		this.container = new Element('div', {
			'class' :'photo_select_container'
		});
		this.content = new Element('ul', {
			'class' :'items'
		});
		this.content.inject(this.container);

		// selected count
		var div = new Element('div', {
			'class' :'select-row'
		});
		
		if(opt.select == 'one') {
		   div.setStyle('display','none');
		}
		
		this.selectors = new Element('span');
		this.selectors.setStyle('visibility','hidden');
		
		this.selectors.set('html',
		      'select <a href="#" class="select-all">all</a> / <a href="#" class="select-none">none</a>');
		
		this.selectCount = new Element('span', {
			'class' :'select-count',
			'text' : $I.transf('[:count] selected', {count: 0})
		});
		
		div.adopt(this.selectors);
		div.adopt(this.selectCount);
		div.inject(this.content, 'before');

		// select all events
		div.getElement('a.select-all').addEvent('click',
				this.selectAll.bindWithEvent(this));

		// select none events
		div.getElement('a.select-none').addEvent('click',
				this.selectNone.bindWithEvent(this));

		this.loading();

		if (this.options.display == 'popup') {
			this.popup = new bebo.ui.Popup( {
				'element' :this.container,
				'title' : $I.transf('Select an Image')
			});
			this.popup.addEvent('ok', this.ok.bindWithEvent(this));
		} else if (this.options.display == 'inline') {

		}
	},

	selectNone : function() {
		this.content.getElements('li.photo').removeClass('selected');
		this.countSelected();
	},

	selectAll : function() {
		this.content.getElements('li.photo').addClass('selected');
		this.countSelected();
	},

	loading : function() {
		this.content.set('html',
		   '<img src="' + $V('CDN', 'prefix') + '/img/throbber_default.gif" /> '+$I.transf("Loading..."));
	},

	show : function() {
		this.active = true;
		if (this.popup) {
			this.popup.show();
		}
		this.render();
	},

	hide : function() {
		if (this.popup) {
			this.popup.close();
		}
		this.container.setStyle('display', 'none');
	},

	render : function() {
		this.loading();

		tmp = new Request.JSON( {
			'url' :this.options.baseUrl + 'show_albums.json?MemberId=' + 
					this.options.memberId + '&no_layout=1',
			onSuccess : function(json) {
				if (this.popup) {
					this.popup
							.setTitle($I.transf('First, pick an album to open:'));
				}
				this.content.empty();

				json.data.albums.each( function(album) {
					var li = new Element('li', {
						'class' :'album'
					});
					li.adopt(new Element('img', {
						'src' :album.cover_file_url
					}));
					li.adopt(new Element('a', {
						'text' :album.album_name,
						'href' :'#'
					}));
					li.adopt(new Element('p', {
						'class' :'small light',
						'text' : ((album.photo_cnt!=1 )  ? 
							$I.transf('([:count] photos)', {count: album.photo_cnt}) : 
							$I.transf('(1 photo)'))
					}));
					li.inject(this.content);

					li.addEvent('click', function(event) {
						this.selectAlbum(album.photo_album_id);
					}.bind(this));

				}.bind(this));
			}.bind(this)
		}).send();
	},

	selectAlbum : function(albumId) {
		this.loading();
		tmp = new Request.JSON( {
			'url' :this.options.baseUrl + 
					'get_album_photos.json?MemberId=' + 
					this.options.memberId + '&AlbumId=' + albumId,

			onSuccess : function(json) {
				if (this.popup) {
					this.popup.setTitle(this.options.select=='many'?$I.transf('Select some photos:'): $I.transf('Select a photo:'));
				}
				this.content.empty();

				json.data.photos.each( function(photo) {
					var li = new Element('li', {
						'class' :'photo'
					});
					li.adopt(new Element('img', {
						'src' :photo.mediumUrl
					}));
					li.adopt(new Element('a', {
						'text' :photo.caption,
						'href' :'#'
					}));
					li.inject(this.content);

					li.addEvent('click', this.photoClick.bindWithEvent(this, li));

					li.store('photoHash', photo);
				}.bind(this));
			}.bind(this)
		}).send();
	},

	photoClick: function(event, ele) {
	   this.togglePhoto(ele);
	   this.countSelected();
	   
      if(this.options.select == 'one') {
	      this.ok();
	   }
	},
	
	countSelected : function() {
		if (!this.selectCount) {
			return; 
		}
		var count = this.content.getElements('li.photo.selected').length;

		this.selectCount.set('html', $I.transf('[:count] selected', {count: count} ));
		return count;
	},

	togglePhoto : function(el) {
		el.toggleClass('selected');
	},

	ok : function() {
		this.sendResults();
		if (this.popup) {
			this.popup.close();
		}
	},

	sendResults : function() {
		var results = new Array();
		this.content.getElements('li.photo.selected').each(
				function(el) {
					results.include(el.retrieve('photoHash'));
				}.bind(this));

		this.hide();
		this.fireEvent('selected', [ this.options.select='one'?results[0]:results ]);
	},

	toElement : function() {
		switch (this.options.display) {
		case 'lightbox':
			return this.popup.toElement();
		case 'inline':
			this.container.setStyle('display', 'block');
			return this.container;
		}
	}
});

/**
 * bebo.ui.PhotoSelector this is a more symantically correct port of our old
 * photo selctor PhotoSelector, with additional options.
 */
bebo.ui.PhotoSelector = new Class(
		{
			Implements : [ Options, Events ],

			options : {
				baseUrl :'/c/photo_selector/',
				selected : [],
				display :'lightbox' // values: 'lightbox', 'inline'
			// TODO: many
			},

			initialize : function(options) {
				this.options.memberId = $V('Member', 'id');
				this.setOptions(options);

				this.adopt();
			},

			adopt : function() {
				this.container = new Element('div', {
					'class' :'photo_select_container',
					'styles' : {
						'display' :'none'
					}
				});
				this.content = new Element('ul', {
					'class' :'items'
				});
				this.content.inject(this.container);

				// selected count
				var div = new Element('div', {
					'class' :'select-row'
				});
				this.selectors = new Element('span');
				this.selectors
						.set(
								'html',
								'select <a href="#" class="select-all">'+$I.transf("all")+'</a> / <a href="#" class="select-none">'+$I.transf("none")+'</a>');
				this.selectCount = new Element('span', {
					'class' :'select-count',
					'text' : $I.transf('[:count] selected', {count: 0})
				});
				div.adopt(this.selectors);
				div.adopt(this.selectCount);
				div.inject(this.content, 'before');

				// select all events
				div.getElement('a.select-all').addEvent('click', function() {
					this.content.getElements('li.photo').addClass('selected');
					this.countSelected();
				}.bind(this));

				// select none events
				div.getElement('a.select-none').addEvent(
						'click',
						function() {
							this.content.getElements('li.photo').removeClass(
									'selected');
							this.countSelected();
						}.bind(this));

				// buttons
				var buttons = new Element('p', {
					'class' :'button-row'
				});
				this.cancel = new Element('span', {'class': 'button-wrapper cancel' });
				this.cancel.set('html', '<input class="button" type="button" value="'+$I.transf("Cancel")+'"/>');
				this.ok = new Element('span' ,{'class': 'button-wrapper'});
				this.ok.set('html', '<input type="submit" class="button" value="'+$I.transf("Ok")+'" />');

				buttons.adopt(this.cancel);
				buttons.adopt(this.ok);
				
				this.container.adopt(buttons);

				this.loading();

				this.cancel.addEvent('click', this.hide.bindWithEvent(this));
				this.ok.addEvent('click', this.sendResults.bindWithEvent(this));

				if (this.options.display == 'lightbox') {
					this.lightbox = new bebo.ui.Lightbox( {
						'element' :this.container,
						'title' :$I.transf('Select an Image')
					});
					this.tip = this.lightbox.element.getElement('h3');
				} else if (this.options.display == 'inline') {

				}
			},

			loading : function() {
				this.content
						.set(
								'html',
								'<img src="' + $V('CDN', 'prefix') + '/img/throbber_default.gif" />'+$I.transf("Loading..."));
			},

			show : function() {
				this.active = true;
				if (this.lightbox) {
					this.lightbox.open();
				}
				this.render();
			},

			hide : function() {
				if (this.lightbox) {
					this.lightbox.close();
				}
				this.container.setStyle('display', 'none');
			},

			render : function() {
				this.loading();

				tmp = new Request.JSON( {
					'url' :this.options.baseUrl + 'show_albums.json?MemberId=' + 
							this.options.memberId + '&no_layout=1',
					onSuccess : function(json) {
						if (this.tip) {
							this.tip.set('html',
									$I.transf('First, pick an album to open:'));
						}
						this.content.empty();

						json.data.albums.each( function(album) {
							var li = new Element('li', {
								'class' :'album'
							});
							li.adopt(new Element('img', {
								'src' :album.cover_file_url
							}));
							li.adopt(new Element('a', {
								'text' :album.album_name,
								'href' :'#'
							}));
							li.adopt(new Element('p', {
								'class' :'small light',
								'text' : ((album.photo_cnt!=1) ? 
									$I.transf( '([:count] photos)', {count: album.photo_cnt }) : 
									$I.transf('(1 photo)'))
							}));
							li.inject(this.content);

							li.addEvent('click', function(event) {
								this.selectAlbum(album.photo_album_id);
							}.bind(this));

						}.bind(this));
					}.bind(this)
				}).send();
			},

			selectAlbum : function(albumId) {
				this.loading();
				tmp = new Request.JSON( {
					'url' :this.options.baseUrl + 
							'get_album_photos.json?MemberId=' + 
							this.options.memberId + '&AlbumId=' + albumId,

					onSuccess : function(json) {
						if (this.tip) {
							this.tip.set('html', $I.transf('Select some photos:'));
						}
						this.content.empty();

						json.data.photos.each( function(photo) {
							var li = new Element('li', {
								'class' :'photo'
							});
							li.adopt(new Element('img', {
								'src' :photo.mediumUrl
							}));
							li.adopt(new Element('a', {
								'text' :photo.caption,
								'href' :'#'
							}));
							li.inject(this.content);

							li.addEvent('click', function(event) {
								this.togglePhoto(li);
								this.countSelected();
							}.bind(this));

							li.store('photoHash', photo);
						}.bind(this));
					}.bind(this)
				}).send();
			},

			countSelected : function() {
				if (!this.selectCount) {
					return;
				}
				var count = this.content.getElements('li.photo.selected').length;
				this.selectCount.set('html', $I.transf('[:count] selected', {count: count}));
				return count;
			},

			togglePhoto : function(el) {
				el.toggleClass('selected');
			},

			sendResults : function() {
				var results = new Array();
				this.content.getElements('li.photo.selected').each(
						function(el) {
							results.include(el.retrieve('photoHash'));
						}.bind(this));

				this.hide();
				this.fireEvent('selected', [ results ]);
			},

			toElement : function() {
				switch (this.options.display) {
				case 'lightbox':
					return this.lightbox.toElement();
				case 'inline':
					this.container.setStyle('display', 'block');
					return this.container;
				}
			}
		});

/**
 * Displays a list of photos in a compact and easy to navigate format
 */
bebo.ui.PhotoScroller = new Class( {
	Implements : [ Options, Events ],

	options : {
		throbber :'/img/throbber_default.gif'
	},

	initialize : function(options) {
		this.setOptions(options);

		this.throbber = new Asset.image($V('CDN', 'prefix') + 
				this.options.throbber);
		$(this.throbber).set('class', 'throbber');

		if (this.options.photos) {
			this.addPhotos(this.options.photos);
		}
	},

	addPhotos : function(photos) {
		photos = $splat(photos);
		this.toElement();

		photos.each( function(p) {
			var li = new Element('li');
			li.store('hash', p); // save the data for later
				li.adopt(new Element('img', {
					'src' :p.smallUrl
				}));
				li.inject(this.photoList);

				li.addEvent('click', this.itemClick.bindWithEvent(this, li));
				p.li = li;
			}.bind(this));

		this.selectPhoto(photos[0]);
	},

	itemClick : function(event, li) {
		this.selectPhoto(li.retrieve('hash'));
	},

	selectPhoto : function(photo) {
		var li = photo.li;
		var asset = li.retrieve('asset');

		this.photoList.getChildren().removeClass('active');
		li.addClass('active');

		if (asset) {
			this.transitionTo(asset);
		} else {
			this.loading();

			asset = new Asset.image(photo.largeUrl, {
				onload : function() {
					this.transitionTo(asset);
				}.bind(this)
			});

			li.store('asset', asset);
		}
	},

	transitionTo : function(asset) { // img tag
		this.photoContainer.empty();
		this.photoContainer.adopt(asset);
	},

	loading : function() { // show throbber
		this.throbber.inject(this.photoContainer);
	},

	toElement : function() {
		if (this.element) {
			return this.element;
		}

		this.element = new Element('div', {
			'class' :'photo-scroller'
		});
		this.photoList = new Element('ul');
		this.photoContainer = new Element('div', {
			'class' :'photo-container'
		});

		this.element.adopt(this.photoList);
		this.element.adopt(this.photoContainer);

		return this.element;
	}
});

/**
 * bebo.ui.Growl USAGE: bebo.ui.Growl.notify('test', {isSticky: true});
 * bebo.ui.Growl.notify.delay(3000, this, new Element('img', { 'src':
 * 'http://i3.bebo.com/042a/13/mediuml/2008/01/28/14/5467981a6735035010ml.jpg',
 * 'styles': {'height': 100,'width': 120} })); bebo.ui.Growl.notify.delay(6000,
 * this, myObject); //myObject must support .toElement()
 */

bebo.ui.Growl = new Class( {
	Implements :Options,

	options : {
		direction :'down'
	},

	initialize : function() {
		$(this).inject('eob-marker', 'before');
	},

	message : function(message, options) {
		var m = new bebo.ui.GrowlMessage(message, options);
		m.show();
		return m;
	},

	toElement : function() {
		this.element = this.element || new Element('ul', {
			'id' :'growl'
		});
		return this.element;
	}
});

bebo.ui.GrowlMessage = new Class( {
	Implements :Options,

	options : {
		delay :5000,
		transitionDuration :400,
		isSticky :false,
		marginBottom :10,
		closeOnClick :true
	},

	initialize : function(message, options) {
		this.setOptions(options);
		this.message = message;
	},

	toElement : function() {
		if ($defined(this.element)) {
			return this.element;
		}

		this.element = new Element('li', {
			styles : {
				'cursor' :'pointer'
			}
		});

		this.element.set('html',
				'<table cellspacing="0" cellpadding="0" border="0" padding="0">' + 
						'<tbody>' + '<tr class="top">' + '<td class="left"/>' + 
						'<td class="center"/>' + '<td class="right"/>' + 
						'</tr>' + '<tr class="middle">' + 
						'<td class="left"/>' + '<td class="center"></td>' + 
						'<td class="right"/>' + '</tr>' + 
						'<tr class="bottom">' + '<td class="left"/>' + 
						'<td class="center"/>' + '<td class="right"/>' + 
						'</tr>' + '</tbody>' + '</table>');

		var c = this.element.getElement('tr.middle td.center');

		if (typeof this.message == 'string') {
			c.set('html', this.message);
		} else {
			$(this.message).inject(c);
		}

		if (this.options.closeOnClick) {
			this.element.addEvent('click', this.hide.bindWithEvent(this));
		}

		return this.element;
	},

	show : function() {
		var el = this.toElement();
	   var growl = bebo.ui.Growl.getInstance();
	   
		el.setStyle('opacity', 0);
		el.inject(growl);
		
		//grab height here
		var height = el.getSize().y;
		
		el.setStyle('height', 0);
		el.inject(growl, growl.options.direction == 'down' ? 'top' : 'bottom');

		this.fx = this.fx || new Fx.Elements(el, {
			'link' :'chain',
			'duration' :this.options.transitionDuration
		});
		this.fx.start( {
			0 : {
				'height' :height,
				'margin-bottom' :this.options.marginBottom
			}
		});
		this.fx.start( {
			0 : {
				'opacity' :1
			}
		});

		if (!this.options.isSticky) {
			this.hide.delay(this.options.delay, this);
		}
	},

	hide : function() {
		this.fx.start( {
			0 : {
				'opacity' :0
			}
		});
		this.fx.start( {
			0 : {
				'height' :0,
				'margin-bottom' :0
			}
		}).chain( function() {
			this.element.destroy();
		}.bind(this));
	}
});

bebo.ui.Growl.getInstance = function() {
	if (!$defined(bebo.ui.Growl.instance)) {
		bebo.ui.Growl.instance = new bebo.ui.Growl();
	}
	return bebo.ui.Growl.instance;
};

// returns bebo.ui.GrowlMessage
bebo.ui.Growl.notify = function(message, options) {
	return bebo.ui.Growl.getInstance().message(message, options);
};

bebo.ui.Button2 = new Class( {
	Implements : [ Options, Events ],

	options : {
		theme :'button', 
		'type' :'button',
		name :'',
		text :'Submit'
	},

	initialize : function(options) {
		this.setOptions(options);
	},

	toElement : function() {
		this.element = this.element || this.buildElement();
		return this.element;
	},

	buildElement : function() {
		var span = new Element('span', {
			'class' :'button-wrapper ' + this.options.theme
		});

		span.addEvent('click', function() {
			this.fireEvent('click', this);
		}.bind(this));

		var input = new Element('input', {
			'class' :'button',
			'type' :this.options.type,
			'name' :this.options.name,
			'value' :this.options.text
		});

		span.adopt(input);

		return span;
	}
});

bebo.ui.Popup = new Class( {
	Implements : [ Options, Events ],

	options : {
		title :"Title",
		className :'popup',
		throbber :'/img/throbber_default.gif',
		showOk : true,
		showCancel :true,
		okAction: function() {
			this.close();
		}
	},

	initialize : function(options) {
		this.setOptions(options);
	},

	toElement : function() {
		this.element = this.element || this.buildElement();
		return this.element;
	},

	buildElement : function() {
		var opt = this.options;
		
		var e = new Element('div', {
			'class' :this.options.className,
			'styles' : {
				'z-index' :'9998',
				'position' :'absolute'
			}
		});

		e.adopt(new Element('span', {
			'class' :'x1'
		}));

		var c = new Element('div', {
			'class' :'popup-content'
		});
		e.adopt(c);

		var hd = new Element('div', {
			'class' :'hd'
		});
		var bd = new Element('div', {
			'class' :'bd'
		});
		var ft = new Element('div', {
			'class' :'ft'
		});
		c.adopt(hd, bd, ft);

		var h3 = new Element('h3', {
			'text' :this.options.title
		});
		var a = new Element('a', {
			'href' :'#',
			'class' :'close'
		});
		a.addEvent('click', this.cancel.bindWithEvent(this));
		hd.adopt(h3, a);

		if(opt.showOk) {
			var ok = new bebo.ui.Button2( {
				'text' : $I.transf('Ok')
			});
			ok.addEvent('click', this.ok.bindWithEvent(this));
			ft.adopt(ok);
		}
		
		if(opt.showCancel) {
			var cancel = new bebo.ui.Button2( {
				'text' : $I.transf('Cancel'),
				'theme' :'cancel'
			});
			cancel.addEvent('click', this.cancel.bindWithEvent(this));
			ft.adopt(cancel);
		}

		this.element = e;
		this.body = bd;

		if (opt.element) {
			opt.element = $(opt.element);
			
			opt.element.setStyles({'display':'block'});
			this.body.adopt(opt.element);
		}
		if(opt.url) {
			this.lazyLoad(opt.url);
		}

		return e;
	},
	
   lazyLoad : function(url) {
      this.body.empty();
      this.body.adopt(
            new Element('img', {'src': this.options.throbber}),
            new Element('span', {'text': $I.transf("Loading...")})
      );

      tmp = new Request.HTML({
         'url' : url,
         update : this.body,
         onComplete : function() {
            this.position.bind(this);
            this.fireEvent('contentLoaded');
         }.bind(this)
      }).send();
   },

   setTitle : function(title) {
      this.toElement().getElement('h3').set('text', title);
   },

   show : function() {
      this.toElement(); // haxorville
      this.element.inject('eob-marker', 'before'); // render to get dimentions

      // display
      this.element.setStyle('display', 'block');
      this.element.setOpacity(1);
	   
      // hide all ads
      $$('div.advertisement').setStyle('visibility', 'hidden');
   
      this.position();
	   
      this.boundPosition = this.boundPosition || this.position.bindWithEvent(this); 
      $(window).addEvent('resize', this.boundPosition);
   },
   
   position: function() {
      var eleSize = this.element.getSize();
      
	  elementLeft = parseInt(window.getWidth() / 2 - eleSize.x / 2, 10);
	  if (this.options.position == 'top') {
	     elementTop = 80;
      } else {
	     // todo: convert to 1/3 top
	     elementTop = parseInt(window.getHeight() / 3 - eleSize.y / 2, 10);
	     elementTop = elementTop < 80 ? 80 : elementTop;
	  }
	  
	  this.element.set('styles', {
	     'left' :elementLeft,
	     'top' :elementTop,
	     'position' :'fixed' // TODO: support 'absolute' for ie6
	  });
   },
   
   ok : function() {
      this.fireEvent('ok', this);
      this.options.okAction.call(this);
   },
   
   cancel : function() {
      this.close();
      this.fireEvent('cancel', this);
   },
   
   close : function() {
	  $(window).removeEvent('resize', this.boundPosition);
	  
      this.element.set('styles', {
      	 opacity :0,
      	 display :'none'
      });
   
      // show ads again
      $$('div.advertisement').setStyle('visibility', 'visible');
      this.fireEvent('close', this);
   },

   hide : function() { this.close(); },

   destroy : function() {
   	this.element.destroy();
   },

   isVisible : function() {
   	return !(this.element.getStyle('display') == 'none');
   },

   toggle : function() {
   	if (!this.isVisible()) {
   		this.open();
   	} else {
   		this.close();
   	}
   }
});

bebo.ui.Lightbox = new Class( {
	Implements : [ Options, Events ],

	options : {
		// title: will add a header
		showClose :true,
		position :'default', // 'default', 'top'
		margin :10, // pixels
		className :'bebobox',
		overlayAll : true
	// overrides margin
	},

	initialize : function(options) {
		this.setOptions(options);
		this.adopt();
	},

	adopt : function() {
		this.element = new Element('div', {
			'class' :this.options.className
		});

		if (!this.options.element) {
			return;
		}

		this.element.inject('eob-marker', 'before');
		this.element.adopt(this.options.element);
		$(this.options.element).set('styles', {
			display :'block'
		});

		if ($defined(this.options.title)) {
			tmp = new Element('h3', {
				'text' :this.options.title
			}).inject(this.element, 'top');
		}

		if (this.options.showClose) {
			this.closeLink = new Element('a', {
				'class':'close',
				'styles' : {
					'position' :'absolute',
					'top' :3,
					'right' :3,
					'z-index' :'9999',
					'cursor' :'pointer'
				}
			});
			this.closeLink.addEvent('click', function() {
				this.close();
				this.fireEvent('close');
			}.bind(this));
			this.closeLink.inject(this.element);
		}
	},

	buildBackground : function(id) {
		var bg = new Element('div', {
			'id' : id,
			'styles' : {
				'z-index' :'9997',
				'background-color' :'black',
				'position' :'absolute'
			}
		});
		bg.inject(this.element, 'after');

		return bg;
	},

	open : function() {
		// init background
		this.bg = $('bebobox_bg');
		if (!this.bg) {
			this.bg = this.buildBackground('bebobox_bg');
		}
		
		this.dropShadow = $('bebobox_ds');
		if (this.dropShadow === null) {
			this.dropShadow = this.buildBackground('bebobox_ds');		
		}
			
		// display
		this.element.setStyle('display', 'block');
		this.element.setOpacity(1);
	
		// hide all ads
		$$('div.advertisement').setStyle('visibility', 'hidden');
		
		// set initial size
		this.sizeAndPosition();
		
		// show and position close button
		this.visible = true;
	},
	
	show : function() {
		this.open();
	},
	
	close : function() {
		this.bg.set('styles', {
			opacity :0,
			display :'none'
		});
		
		this.dropShadow.set('styles', {
			opacity :0,
			display :'none'
		});
		
		this.element.set('styles', {
			opacity :0,
			display :'none'
		});
		this.visible = false;
		
		// show ads again
		$$('div.advertisement').setStyle('visibility', 'visible');
	},
	
	hide : function() { this.close(); },
	
	destroy : function() {
		this.element.destroy();
	},
	
	sizeAndPosition : function() {
		
		var eleSize = this.element.getSize();
		
		// center
		elementLeft = parseInt(window.getWidth() / 2 - eleSize.x / 2, 10);
		if (this.options.position == 'top') {
			elementTop = 80;
		} else {
				// todo: convert to 1/3 top
			elementTop = parseInt(window.getHeight() / 3 - eleSize.y / 2, 10);
			elementTop = elementTop < 80 ? 80 : elementTop;
		}
		
		this.element.set('styles', {
			'left' :elementLeft,
			'top' :elementTop,
			'position' :'fixed'
		});
		
		this.bg.set('styles', {
			'display' :'block',
			'position' :'fixed',
			'top' :this.options.overlayAll ? 0 : elementTop - this.options.margin,
			'left' :this.options.overlayAll ? 0 : elementLeft - this.options.margin,
			'width' :this.options.overlayAll ? window.getWidth() : eleSize.x + 
					this.options.margin * 2,
			'height' :this.options.overlayAll ? window.getHeight() : eleSize.y + 
					this.options.margin * 2,
			'opacity' :0.5
		});	
		
		this.dropShadow.set('styles', {
			'display' : this.options.overlayAll? 'block' : 'none',
			'position' :'fixed',
			'top' : elementTop - this.options.margin,
			'left' : elementLeft - this.options.margin,
			'width' : eleSize.x + this.options.margin * 2,
			'height' : eleSize.y + this.options.margin * 2,
			'opacity' :0.5
		});		
	},
	
	toggle : function() {
		if (!this.visible) {
			this.open();
		} else {
			this.close();
		}
	}
});

/**
 * 
 */
bebo.ui.ConfirmationBox = new Class( {
	Extends :bebo.ui.Lightbox,

	options : {
		className :'bebobox confirm',
		message :'Message Body',
		okText : $I.transf('OK'),
		showCancel: true,
		cancelText : $I.transf('Cancel'),
		onOk: function() {
			this.close();
			this.fireEvent('close');
		},
		onCancel : function() {
			this.close();
			this.fireEvent('close');
		}
	},

	initialize : function(options) {
		this.setOptions(options);

		var container = new Element('div');
		this.messageElem = new Element('p', {
			'text' :this.options.message,
			'class' : 'box-bd'
		});
		container.adopt(this.messageElem);

		// buttons
	   	this.buttons = new Element('p', {
	   		'class' :'button-row'
	   	});
	   	this.ok = new Element('span', {
	   		'class' :'button-wrapper',
	   		'html' : '<input class="button" type="button" value="'+this.options.okText+'"/>'
	   	});
	   	this.buttons.adopt(this.ok);
		this.boundClickOk = this.clickOk.bind(this);
	   	this.ok.addEvent('click', this.boundClickOk);
	   
	   	if (this.options.showCancel) {
		   	this.cancel = new Element('span', {
		   		'class' :'button-wrapper cancel',
		   		'html' : '<input class="button" type="button" value="'+this.options.cancelText+'"/>'
		   	}); 
		   	this.buttons.adopt(this.cancel);
		   	this.cancel.addEvent('click', function() {
		   		this.fireEvent('cancel', this);
		   	}.bind(this));
	   	}
	   	container.adopt(this.buttons);
	   	this.options.element = container;
	   	this.parent(this.options);
   },
   
   updateMessage : function(newMsg) {
	   this.messageElem.set('text',newMsg);
	   this.sizeAndPosition();
   },
   
   updateMessageNoButtons : function(newMsg) {
	   this.buttons.setStyle('display','none');
	   this.updateMessage(newMsg);
   },
   
   updateMessageCloseButton : function(newMsg) {
	   this.buttons.setStyle('display',null);
 	   this.ok.setStyle('display','none');
 	   this.cancel.getElement('input').set('value',$I.transf('Close'));
	   this.updateMessage(newMsg);
   },   
   
   updateOkText: function(text) {
	   this.ok.getElement('input').set('value', text);
   },
   
   clickOk: function(e) {
   		this.fireEvent('ok', this);
   },
   
   removeOkClickEvent: function(e) {
	   this.ok.removeEvent('click', this.boundClickOk);
   }
});

/**
 * Examples: new bebo.ui.Button({text: 'Get Started Now'}); new
 * bebo.ui.Button({element: 'get-started'});
 */
bebo.ui.Button = new Class( {
	Implements : [ Options, Events ],

	options : {
		text : 'Submit',
		onClick :this.click
	},

	initialize : function(options) {
		this.setOptions(options);

		if ($defined(options.element)) {
			var el = $(options.element);
			this.options.text = el.get('text');
			$(this).inject(el, 'after');
			el.destroy();
		}
	},

	toElement : function(text) {
		text = this.options.text;

		var a = new Element('a', {
			'href' :'#',
			'class' :'submit-button'
		});
		a.addEvent('click', function() {
			this.fireEvent('click');
		}.bind(this));

		tmp = new Element('span', {
			'text' :text
		}).inject(a);

		return a;
	},

	click : function() {
		alert('clicked: ' + this.text);
	}
});

/* rounding */
bebo.ui.Rounder = new Class(
		{
			initialize : function() {
			},

			round : function(el) {
				var content = new Element('div', {
					'class' :'content'
				});
				content.set('html', el.get('html'));
				el.empty();
				el.adopt(content);

				tmp = new Element(
						'b',
						{
							'class' :'rtop',
							'html' :'<b class="r1"></b> <b class="r2"></b> <b class="r3"></b> <b class="r4"></b>'
						}).inject(el, 'top');

				tmp = new Element(
						'b',
						{
							'class' :'rbottom',
							'html' :'<b class="r4"></b><b class="r3"></b><b class="r2"></b><b class="r1"></b>'
						}).inject(el, 'bottom');
			},

			roundElementsBySelector : function(selector) {
				$$(selector).each( function(el) {
					this.round(el);
				}.bind(this));
			}
		});

bebo.ui.Rounder.getInstance = function() {
	if (!$defined(bebo.ui.Rounder.instance)) {
		bebo.ui.Rounder.instance = new bebo.ui.Rounder();
	}
	return bebo.ui.Rounder.instance;
};
/* rounding: END */

bebo.ui.TitleRotator = new Class( {
	delay :3000, // ms

	initialize : function() {
	},

	addMessage : function(message) {
		if (!$defined(this.messages)) {
			this.title = document.title;
			this.messages = [ document.title ];
		}
		this.messages.include(message);

		if (!this.rotating) {
			this.stopNext = false;
			this.rotate();
		}
	},

	rotate : function() {
		this.rotating = true;

		if (this.stopNext) {
			this.stopNext = null;
			this.rotating = null;
			return;
		}

		if (!$defined(this.position) || 
				this.position >= this.messages.length - 1) {
			this.position = -1;
		}
		this.position = this.position + 1;
		document.title = this.messages[this.position];
		this.rotate.delay(this.delay, this);
	},

	stop : function() {
		if (!this.rotating) {
			return;
		}

		this.stopNext = true;
		document.title = this.title;

		if (!$defined(this.messages)) {
			return;
		}
		this.messages.empty();
		this.messages = null;
	},

	hasMessage : function(message) {
		if (!$defined(this.messages)) {
			return false;
		}
		return this.messages.contains(message);
	},

	removeMessage : function(message) {
		if (!$defined(this.messages)) {
			return false;
		}
		this.messages.erase(message);
	}
});

bebo.ui.TitleRotator.getInstance = function() {
	if (!$defined(bebo.ui.TitleRotator.instance)) {
		bebo.ui.TitleRotator.instance = new bebo.ui.TitleRotator();
	}
	return bebo.ui.TitleRotator.instance;
};

bebo.ui.Util = {
	hideAdsForOverlay : function() {
		if (!Browser.Engine.trident) {
			return;
		}
		$$('div.advertisement').setStyle('visibility', 'hidden');
	},

	showAds : function() {
		$$('div.advertisement').setStyle('visibility', 'visible');
	}
};

var BeboModule = {
	show : function(id, profileMemberId, set) {
		var e = $('content_' + id);
		var a = $(id);
		var p = $('content_' + id);

		var url = "/c/profile/minimize?ProfileMemberId=" + profileMemberId + 
				"&ModuleId=" + id;
		var transaction = null;

		var arrow = a.getElement(".arrow");
		if (!arrow) {
			return;
		}

		arrow.addClass("arrow-down");
		arrow.removeClass("arrow-right");
		e.removeClass("not-shown");
		e.addClass("shown");

		if (e.get('text').trim() === "") {
			p.innerHTML = "<div class=\"content\">"+$I.transf("Loading...")+"</div>";
			var content_url = null;
			if (id.contains('app')) {
				content_url = "/c/apps/get_app_content?ProfileMemberId=" + 
						profileMemberId + "&AppId=" + id;
				if (set !== false) {
					url += "&HideModule=N";
					transaction = YAHOO.util.Connect.asyncRequest('GET',
							url, null, null);
				}
			} else {
				content_url = url += "&GetContent=Y&HideModule=N";
			}
			tmp = new Request.HTML( {
				url :content_url,
				method :'GET',
				update :p,
				evalScripts :true
			}).send();
		} else {
			if (set !== false) {
				url += "&HideModule=N";
				transaction = YAHOO.util.Connect.asyncRequest('GET', url,
						null, null);
			}
		}
	},
	
	hide : function(id, profileMemberId) {
		var e = $('content_' + id);

		var a = $(id);

		var arrow = a.getElement(".arrow-down");
		if (!arrow) {
			return;
		}

		arrow.addClass("arrow-right");
		arrow.removeClass("arrow-down");
		e.removeClass("shown");
		e.addClass("not-shown");

		var url = "/c/profile/minimize?ProfileMemberId=" + profileMemberId + 
				"&ModuleId=" + id;
		url += "&HideModule=Y";
		transaction = YAHOO.util.Connect.asyncRequest('GET', url, null,
				null);

	},
	
	hideshow : function(id, profileMemberId) {
		var e = $('content_' + id);
		if (e.hasClass('not-shown')) {
			this.show(id, profileMemberId);
		} else {
			this.hide(id, profileMemberId);
		}
	}
};

/* begin scroll to apps - jason */
// todo: namespace
var scrollToApp = function(id, profileMemberId) {
	if (typeof profileScroll == 'undefined') {
		profileScroll = new Fx.Scroll(window, {
			wait :false,
			duration :1000,
			offset : {
				'y' :-50
			},
			transition :Fx.Transitions.Cubic.easeOut
		});
	}

	if ($defined($(id))) {
		BeboModule.show(id, profileMemberId, false);
		profileScroll.toElement(id);
	} else {
		var div = new Element('div');
		div.inject('Comment', 'before');

		tmp = new Request.HTML( {
			'url' :"/c/apps/get_app_content?ProfileMemberId=" + profileMemberId + 
					"&AppId=" + id + "&AsProfileModule=Y&Display=N",
			method :'get',
			evalScripts :true,
			update :div,
			onComplete : function(resp) {
				// fix this
			BeboModule.show(div.getChildren()[0], profileMemberId, false);
			profileScroll.toElement(div);
		}
		}).send();
	}
};
/* end scroll to apps */

/* ad placment */
var adMoveTimer = null; // will hold reference to interval that checks for new
// ad content

// this code moves ads rendered at the end of the document to the spot in the
// page where they belong
function _moveAd(startNode, destinationNode, endNodeId) {
	if (destinationNode === null) {
		return;
	}

	var curNode = $(startNode.nextSibling);
	while (curNode !== null && curNode.id !== "ad-block-hack-end") {
		// store nextSibling now, because it will be different if elCurrent is
		// removed from the DOM and appended to elAdBlock
		var nextSibling = curNode.nextSibling;

		// copy all content except script tags to the ad-block container
		if (curNode.nodeName !== 'SCRIPT') {

			// adding a try/catch for Ken's WebTest
			try {

				// try turning on and off display to make sure that flash
				// anmiations start after they are moved
				var oldDisplay = null;
				if (curNode.nodeType != 3) { // node type 3 is #text
					oldDisplay = curNode.style.display;
					curNode.style.display = "none";
				}

				destinationNode.appendChild(curNode);

				// set the display back to it's previous value
				if (curNode.nodeType != 3) { // #text node
					curNode.style.display = oldDisplay;
				}

			} catch (e) {
			}

		}
		curNode = nextSibling;
	}
	return;
}

// try to move the ad when the domready event fires, which is when the browser
// has finished parsing the HTML document,
// but before all of the images and external files have loaded
$(window).addEvent("domready", function() {

	var startNode = $('ad-block-hack-begin');
	if (!$defined(startNode)) {
		return;
	}

	var destinationNode = $("ad-spot-0");
	var endNodeId = "ad-block-hack-end";

	_moveAd(startNode, destinationNode, endNodeId);
});

// Unfortunately we need to be prepared for domready to fire too early and not
// see the ad content in the page.
// We'll define the same handler for window.onload too in case this happens. If
// domready succeedes, then this will just return.
$(window).addEvent("load", function() {

	var startNode = $('ad-block-hack-begin');
	var destinationNode = $("ad-spot-0");
	var endNodeId = "ad-block-hack-end";

	if(!destinationNode) { return; }
	
	_moveAd(startNode, destinationNode, endNodeId);

	// in IE6 and IE7, keep checking for ad content to move into its spot
	if (Browser.Engine.trident) {
	   	setInterval( function() {
	   	   _moveAd(startNode, destinationNode, endNodeId);
	   	}, 1000);
	}
});

/* ad placement: END */

function display(elementName, displayParam) {
	var elem = document.getElementById(elementName);

	if (elem !== null) {
		elem.style.display = displayParam;
	} else {
		alert("could not find " + elementName);
	}
	return false;
}

function hide(id) {
	return display(id, "none");
}

function show(id) {
	return display(id, "");
}

function toggle_element(element) {
	var display = element.style.display;
	if (display == "none") {
		element.style.display = "";
	} else {
		element.style.display = "none";
	}
}

function toggle(id) {
	var element = document.getElementById(id);
	if (element !== null) {
		toggle_element(element);
	} else {
		alert("could not find " + id);
	}
}

function hiFlag() {
	var arrow = document.getElementById("lang_arrow");
	arrow.src = "/img/explore_arrow_white.gif";
}

function lowFlag() {
	var arrow = document.getElementById("lang_arrow");
	arrow.src = "/img/explore_arrow_grey.gif";
}

function showFlagsDiv(siteElem) {
	var tabBar = document.getElementById('tab-bar');
	var flagDiv = document.getElementById('flagDiv');

	if (flagDiv !== null) {
		flagDiv.style.left = (tabBar.offsetLeft + 752) + "px";
		toggle_element(flagDiv);
	} else {
		alert("flagDiv not found");
	}
}

function verifySearch(searchForm, searchDefaultText) {
	// make sure not a search for '' or 'Search...'
	if (searchForm.SearchTerm.value === searchDefaultText || 
			searchForm.SearchTerm.value === '') {
		searchForm.SearchTerm.value = '';
		searchForm.SearchTerm.focus();
		return false;
	} else {
		return true;
	}
}

var BeboJS = {
	show : function(name) {
		var el = document.getElementById(name);
		if (el) {
			el.style.display = 'inline';
		}
	},
	hide : function(name) {
		var el = document.getElementById(name);
		if (el) {
			el.style.display = 'none';
		}
	}
};

var ampUnescaped = '&';

/* BEGIN: flags */
// TODO: cleanup and convert to namespace
// TODO: this could be simplified using moo tools
function closeFlagDiv() {
	var flagDiv = document.getElementById('flagDiv');
	if (!flagDiv) {
		return;
	}
	if (flagDiv && flagDiv.style.display != 'none') {
		flagDiv.style.display = 'none';
	}
}

function _hideFlagsOnDocumentClick(e) {
	if (document.getElementById !== null) { 
		if (!$('flagDiv')) {
			return;
		}
		var element = e.target || e.srcElement;
		var flagDiv = document.getElementById("flagDiv");
		if (!flagDiv) {
			return;
		}
		if (element.className !== null && 
				element.className.indexOf('flagDiv') === -1 && 
				element.className.indexOf('currentFlag') === -1 && 
				flagDiv.style.display === "") {
			closeFlagDiv();
		}
	}
}

/* BEGIN: mp3 player */
// TODO: cleanup and convert to namespace
// JavaScript Document
var swfButtonIndex = 0;
function getFlashMovieObject(movieName) {
	if (window.document[movieName]) {
		return window.document[movieName];
	}
	if (navigator.appName.indexOf("Microsoft Internet") == -1) {
		if (document.embeds && document.embeds[movieName]) {
			return document.embeds[movieName];
		}
	} else { 
		return document.getElementById(movieName);
	}
}

function getPlayer(vars, title) {
	if (vars === "") {
		var flashMovie = getFlashMovieObject("bebo_player");
		vars = flashMovie.GetVariable("_root.vars");
	}

	function flashObject(win, type) {
		if (type == "button") {
			swfButtonIndex++;
			idName = "bebo_player_button" + swfButtonIndex;
			swfWidth = 20;
			swfHeight = 20;
			swfName = "/mp3_player_button";
			vars = "songurl=" + vars;
		} else {
			idName = "bebo_player";
			swfWidth = 404;
			swfHeight = 354;
			swfName = "/mp3_player";
		}
		win.document
				.write('<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="' + 
						swfWidth + 
						'" height="' + 
						swfHeight + 
						'" id="' + 
						idName + '" align="middle">');
		win.document
				.write('<param name="allowScriptAccess" value="sameDomain" />');
		win.document.write('<param name="FlashVars" value="' + vars + '" />');
		win.document
				.write('<param name="movie" value="' + swfName + '.swf" />');
		win.document.write('<param name="quality" value="high" />');
		win.document.write('<param name="bgcolor" value="#000000" />');
		win.document
				.write('<embed src="' + 
						swfName + 
						'.swf" quality="high" FlashVars="' + 
						vars + 
						'" bgcolor="#000000" width="' + 
						swfWidth + 
						'" height="' + 
						swfHeight + 
						'" name="' + 
						idName + 
						'" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />');
		win.document.write('</object>');
	}
	if (title) {
		winww = 404;
		winhh = 354;

		LeftPosition = (screen.width) ? (screen.width - winww) / 2 : 100;
		TopPosition = (screen.height) ? (screen.height - winhh) / 2 : 100;

		settings = 'width=' + 
				winww + 
				',height=' + 
				winhh + 
				',top=' + 
				TopPosition + 
				',left=' + 
				LeftPosition + 
				',scrollbars=no,location=no,directories=no,status=no,menubar=no,toolbar=no,resizable=no';

		win = open("", 'bebo_player', settings);
		win.document.write('<head>');
		win.document
				.write('<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />');
		win.document.write('<title>' + title + '</title>');
		win.document.write('</head>');
		win.document
				.write('<body bgcolor="#000000" leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">');
		flashObject(win);
		win.document.write('</body>');
		win.document.write('</html>');
		win.focus();
	} else {
		if (vars.substr(0, 4).toLowerCase() == "http") {
			flashObject(window, "button");
		} else {
			flashObject(window);
		}
	}
}

function getPlayer2(vars, title, htmlParentId) {
	if (vars === "") {
		var flashMovie = getFlashMovieObject("bebo_player");
		vars = flashMovie.GetVariable("_root.vars");
	}

	function flashObject(win, type, parentId) {
		if (type == "button") {
			swfButtonIndex++;
			idName = "bebo_player_button" + swfButtonIndex;
			swfWidth = 20;
			swfHeight = 20;
			swfName = "/music_player_button.swf?v=4";
			vars = vars;
		} else {
			idName = "bebo_player";
			swfWidth = 404;
			swfHeight = 354;
			swfName = "/mp3_player.swf";
		}

		if (parentId) {
			// aplatti: if an parent element ID was supplied, set the HTML
			// directly. (Used for MP3 buttons in modules dynamically added
			// through expand/collapse)

			var mp3Html = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="' + 
					swfWidth + 
					'" height="' + 
					swfHeight + 
					'" id="' + 
					idName + 
					'" align="middle">' + 
					'<param name="allowScriptAccess" value="sameDomain" />' + 
					'<param name="FlashVars" value="' + 
					vars + 
					'" />' + 
					'<param name="movie" value="' + 
					swfName + 
					'" />' + 
					'<param name="quality" value="high" />' + 
					'<param name="bgcolor" value="#000000" />' + 
					'<embed src="' + 
					swfName + 
					'" quality="high" FlashVars="' + 
					vars + 
					'" bgcolor="#000000" width="' + 
					swfWidth + 
					'" height="' + 
					swfHeight + 
					'" name="' + 
					idName + 
					'" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" swliveconnect="true"/>' + 
					'</object>';

			var parentElem = document.getElementById(parentId);
			if (parentElem) {
				parentElem.innerHTML = mp3Html;
			}

		} else {
			win.document
					.write('<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="' + 
							swfWidth + 
							'" height="' + 
							swfHeight + 
							'" id="' + 
							idName + '" align="middle">');
			win.document
					.write('<param name="allowScriptAccess" value="sameDomain" />');
			win.document
					.write('<param name="FlashVars" value="' + vars + '" />');
			win.document
					.write('<param name="movie" value="' + swfName + '" />');
			win.document.write('<param name="quality" value="high" />');
			win.document.write('<param name="bgcolor" value="#000000" />');
			win.document
					.write('<embed src="' + 
							swfName + 
							'" quality="high" FlashVars="' + 
							vars + 
							'" bgcolor="#000000" width="' + 
							swfWidth + 
							'" height="' + 
							swfHeight + 
							'" name="' + 
							idName + 
							'" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" swliveconnect="true"/>');
			win.document.write('</object>');
		}
	}
	if (title) {
		winww = 404;
		winhh = 354;

		LeftPosition = (screen.width) ? (screen.width - winww) / 2 : 100;
		TopPosition = (screen.height) ? (screen.height - winhh) / 2 : 100;

		settings = 'width=' + 
				winww + 
				',height=' + 
				winhh + 
				',top=' + 
				TopPosition + 
				',left=' + 
				LeftPosition + 
				',scrollbars=no,location=no,directories=no,status=no,menubar=no,toolbar=no,resizable=no';

		win = open("", 'bebo_player', settings);
		win.document.write('<head>');
		win.document
				.write('<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />');
		win.document.write('<title>' + title + '</title>');
		win.document.write('</head>');
		win.document
				.write('<body bgcolor="#000000" leftmargin="0" topmargin="0" rightmargin="0" bottommargin="0">');
		flashObject(win);
		win.document.write('</body>');
		win.document.write('</html>');
		win.focus();
	} else {
		if (vars.substr(0, 4).toLowerCase() == "song") {
			flashObject(window, "button", htmlParentId);
		} else {
			flashObject(window);
		}
	}
}

function playTrack(song) {
	if (song) {
		var objs = document.getElementsByTagName("object");
		var numObjs = objs.length;
		for ( var i = 0; i < numObjs; i++) {
			var curObj = objs[i];
			if (curObj.id.indexOf("bebo_player_button") === 0) {

				var flashMovie = getFlashMovieObject(curObj.id);

				if (flashMovie.GetVariable("_root.haskey") == "play") {
					if (song == flashMovie.GetVariable("_root.songId")) {
						flashMovie.SetVariable("_root.control", "play");
					}
				}
			}
		}
	}
}

function playTrack2(song) {
	if (song) {
		var objs = document.getElementsByTagName("object");
		var numObjs = objs.length;
		for ( var i = 0; i < numObjs; i++) {
			var curObj = objs[i];
			if (curObj.id.indexOf("bebo_player_button") === 0) {

				var flashMovie = getFlashMovieObject(curObj.id);

				if (flashMovie.GetVariable("_root.haskey") == "play") {
					if (song == flashMovie.GetVariable("_root.songId")) {
						flashMovie.SetVariable("_root.control", "play");
					}
				}
			}
		}
	}
}

function stopTrack(song) {
	var objs = document.getElementsByTagName("object");
	var numObjs = objs.length;
	for ( var i = 0; i < numObjs; i++) {
		var curObj = objs[i];
		if (curObj.id.indexOf("bebo_player_button") === 0) {
			var flashMovie = getFlashMovieObject(curObj.id);
			if (flashMovie && flashMovie.GetVariable("_root.haskey") == "play") {
				if (song != flashMovie.GetVariable("_root.songurl")) {
					flashMovie.SetVariable("_root.control", "stop");
				}
			}
		}
	}
}

function stopTrack2(song) {

	// aplatti: changed this to remove the need for a sequential number suffix
	// on the mp3 player button objects.

	var objs = document.getElementsByTagName("object");
	var numObjs = objs.length;
	for ( var i = 0; i < numObjs; i++) {
		var curObj = objs[i];
		if (curObj.id.indexOf("bebo_player_button") === 0) {

			var flashMovie = getFlashMovieObject(curObj.id);

			if (flashMovie.GetVariable("_root.haskey") == "play") {
				if (song != flashMovie.GetVariable("_root.songId")) {
					flashMovie.SetVariable("_root.control", "stop");
				}
			}
		}
	}
}

/* END mp3 player */

var LangSelector = new Class( {

	initialize : function(element) {
		this.selectorEl = $(element);

		this.currentLangEl = this.selectorEl.getElement('li'); // first li node
		this.langListEl = this.selectorEl.getElement('ul'); // should always be a 'ul'
		this.boundMouseLeave = this.mouseLeave.bind(this);

		this.attach();
	},

	attach : function() {
		this.selectorEl.addClass('lang-selector');
		this.currentLangEl.addClass('lang-current');
		this.langListEl.addClass('lang-list');

		this.selectorEl.setStyle("pointer", "cursor");
		this.currentLangEl.addEvent('click', this.titleClick
				.bindWithEvent(this));
	},

	titleClick : function(event) {
		if (this.selectorEl.hasClass('active')) {
			this.hide();
		} else {
			this.selectorEl.addClass('active');
			this.langListEl.setStyle('display', 'block');
			event.stopPropagation();
			$(document.body).addEvent('click', this.hide
					.bindWithEvent(this));
		}
	},

	mouseLeave : function(event) {
		this.hide();
	},

	hide : function() {
		this.selectorEl.removeClass('active');
		this.langListEl.setStyle('display', 'none');

		this.selectorEl.removeEvent('mouseleave', this.boundMouseLeave);
	}
});

bebo.ui.TextDropShadow = new Class({
   options: {
      color: '#333',
      left: 1,
      top: 1,
      position: 'absolute'
   },
    
   initialize: function(obj, options){
      this.setOptions(options);
      this.createDropShadows(obj);
   },
    
   createDropShadows: function(obj){
      if('element' == $type(obj)) {
         this.applyDropShadow(obj);
      } else if('array' == $type(obj)) {
         obj.each( function(el) {
            this.applyDropShadow(el);
         }, this);
      } else {
         return false;
      }
   },
    
   applyDropShadow: function(el){
      var size = el.getSize();
      var original = el.clone();
      var shadow = el.clone();
    
      var offsetY = this.options.top ? this.options.top.toInt() : this.options.bottom.toInt();
      if(offsetY < 0) { offsetY = offsetY * (-1); }
    
      var offsetX = this.options.left ? this.options.left.toInt() : this.options.right.toInt();
      if(offsetX < 0) { offsetX = offsetX * (-1); }
    
      var container = new Element('div', {
         'styles': {
            position: 'relative',
            left: 0,
            top: 0,
            height: size.y + offsetY,
            width: size.x + offsetX
         }
      });
    
      original.setStyles({position: 'absolute', left: 0, top: 0});
      shadow.setStyles(this.options);
    
      container.adopt(shadow).adopt(original);
      container.injectAfter(el);
      el.destroy();
   }
});


bebo.ui.GlobalSearchBox = new Class( {
	initialize : function(form) {
      this.element = $(form);
      
      if(!this.element) { return; }
      
		this.input = this.element.getElement('input');
		this.button = this.element.getElement('button');
		
		this.text = this.input.get('value');

		this.input.addEvent('focus', this.focus.bindWithEvent(this));
		this.input.addEvent('blur', this.blur.bindWithEvent(this));
		
		this.button.addEvent('click', this.submit.bindWithEvent(this));
	},
	
	submit: function(event) {
	   if(this.input.get('value') != this.text) { return; }
	   
      event.preventDefault();
      this.focus();
      this.input.focus();
	},

	focus : function() {
		if (this.input.get('value') == this.text) {
			this.input.set('value', '');
			this.input.removeClass('inactive');
		}
	},

	blur : function() {
		if (this.input.get('value') === '') {
			this.input.set('value', this.text);
			this.input.addClass('inactive');
		}
	}
});

// TODO: this should eventually be moved to its own JS file since bebo.js is
// becoming more of a library
YAHOO.util.Event.onContentReady('more-menu', function() {
	tmp = new bebo.ui.DropDown(this);
});
YAHOO.util.Event.onContentReady('yahoo-search-form', function() {
	tmp = new bebo.ui.GlobalSearchBox(this);
});

$(document).addEvent('endofbody', function(event) {
	$$("ul.lang-selector").each( function(el) {
		tmp = new LangSelector(el);
	});
});

// There is a well known bug in the Internet Explorer implementation of the getElementById() method, which, contrary to the W3C standard, 
// allows the method to return an element if the elementÕs id attribute _or_ its _name_ attribute matches the id we are looking for.
// We will override IEÕs native getElementById method with one that behaves properly according to W3C standards. (jv)
// Update: Turns out Opera has the same problem.

if (/msie/i.test (navigator.userAgent) || typeof(window.opera) != 'undefined') {//only override IE and Opera
	document.nativeGetElementById = document.getElementById;
	document.getElementById = function(id) {
		var elem = document.nativeGetElementById(id);
		if(elem) {
			//make sure that it is a valid match on id
			if(elem.attributes['id'] && elem.attributes['id'].value == id) {
				return elem;
			} else {
				//otherwise find the correct element
				for(var i=1;i<document.all[id].length;i++) {
					if(document.all[id][i].attributes['id'] && document.all[id][i].attributes['id'].value == id) {
						return document.all[id][i];
					}
				}
			}
		}
		return null;
	};
}

// override Mootools Sortables start method to pass preventDefault option into Drag.Move to fix IE drag issue with images
Sortables.implement({
	start: function(event, element){
		if (!this.idle) {return;}
		this.idle = false;
		this.element = element;
		this.opacity = element.get('opacity');
		this.list = element.getParent();
		this.clone = this.getClone(event, element);
	
		this.drag = new Drag.Move(this.clone, {
			preventDefault: true,
			snap: this.options.snap,
			container: this.options.constrain && this.element.getParent(),
			droppables: this.getDroppables(),
			onSnap: function(){
				event.preventDefault();
				this.clone.setStyle('visibility', 'visible');
				this.element.set('opacity', this.options.opacity || 0);
				this.fireEvent('start', [this.element, this.clone]);
			}.bind(this),
			onEnter: this.insert.bind(this),
			onCancel: this.reset.bind(this),
			onComplete: this.end.bind(this)
		});
	
		this.clone.inject(this.element, 'before');
		this.drag.start(event);
	}	
});
