// 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
	_transfWithArgs: function(/*String*/ string, /*Object*/ transArgs , /*String?*/ unit) {
		var replacer = function(string) {
	  		$each(transArgs||{}, function(replacement, placeholder){
	  			string = string.split('[:'+placeholder+']').join(replacement);
			});
	  		return string;
	  	};
	  	return replacer($I._transfWithoutArgs(string, unit));
	},
	_transfWithoutArgs: function(/*String*/ string, /*String?*/ unit) {
		unit = unit || 'general';
		return (typeof I18NLocals=='object' && I18NLocals[unit]) && (I18NLocals[unit][string] || string) || string;
	},
	transf: function(/*String*/ string /*... transArgs, unit */) {
		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: Element.Shortcuts.js
   Extends the Element native object to include some shortcut methods.

License:
   http://clientside.cnet.com/wiki/cnet-libraries#license
*/

Element.implement({
   isVisible: function() {
      return this.getStyle('display') != 'none';
   },
   toggle: function() {
      return this[this.isVisible() ? 'hide' : 'show']();
   },
   hide: function() {
      var d;
      try {
         //IE fails here if the element is not in the dom
         if ('none' != this.getStyle('display')) d = this.getStyle('display');
      } catch(e){}
      this.store('originalDisplay', d||'block'); 
      this.setStyle('display','none');
      return this;
   },
   show: function(display) {
      original = this.retrieve('originalDisplay')?this.retrieve('originalDisplay'):this.get('originalDisplay');
      this.setStyle('display',(display || original || 'block'));
      return this;
   },
   swapClass: function(remove, add) {
      return this.removeClass(remove).addClass(add);
   },
   //TODO
   //DO NOT USE THIS METHOD
   //it is temporary, as Mootools 1.1 will negate its requirement
   fxOpacityOk: function(){
      return !Browser.Engine.trident4;
   }
});


/*
Script: Element.Measure.js
   Extends the Element native object to include methods useful in measuring dimensions.

License:
   http://clientside.cnet.com/wiki/cnet-libraries#license
*/

Element.implement({

   expose: function(){
      if (this.getStyle('display') != 'none') return $empty;
      var before = {};
      var styles = { visibility: 'hidden', display: 'block', position:'absolute' };
      //use this method instead of getStyles 
      $each(styles, function(value, style){
         before[style] = this.style[style]||'';
      }, this);
      //this.getStyles('visibility', 'display', 'position');
      this.setStyles(styles);
      return (function(){ this.setStyles(before); }).bind(this);
   },
   
   getDimensions: function(options) {
      options = $merge({computeSize: false},options);
      var dim = {};
      function getSize(el, options){
         return (options.computeSize)?el.getComputedSize(options):el.getSize();
      };
      if(this.getStyle('display') == 'none'){
         var restore = this.expose();
         dim = getSize(this, options); //works now, because the display isn't none
         restore(); //put it back where it was
      } else {
         try { //safari sometimes crashes here, so catch it
            dim = getSize(this, options);
         }catch(e){}
      }
      return $chk(dim.x)?$extend(dim, {width: dim.x, height: dim.y}):$extend(dim, {x: dim.width, y: dim.height});
   },
   
   getComputedSize: function(options){
      options = $merge({
         styles: ['padding','border'],
         plains: {height: ['top','bottom'], width: ['left','right']},
         mode: 'both'
      }, options);
      var size = {width: 0,height: 0};
      switch (options.mode){
         case 'vertical':
            delete size.width;
            delete options.plains.width;
            break;
         case 'horizontal':
            delete size.height;
            delete options.plains.height;
            break;
      };
      var getStyles = [];
      //this function might be useful in other places; perhaps it should be outside this function?
      $each(options.plains, function(plain, key){
         plain.each(function(edge){
            options.styles.each(function(style){
               getStyles.push((style=="border")?style+'-'+edge+'-'+'width':style+'-'+edge);
            });
         });
      });
      var styles = this.getStyles.apply(this, getStyles);
      var subtracted = [];
      $each(options.plains, function(plain, key){ //keys: width, height, plains: ['left','right'], ['top','bottom']
         size['total'+key.capitalize()] = 0;
         size['computed'+key.capitalize()] = 0;
         plain.each(function(edge){ //top, left, right, bottom
            size['computed'+edge.capitalize()] = 0;
            getStyles.each(function(style,i){ //padding, border, etc.
               //'padding-left'.test('left') size['totalWidth'] = size['width']+[padding-left]
               if(style.test(edge)) {
                  styles[style] = styles[style].toInt(); //styles['padding-left'] = 5;
                  if(isNaN(styles[style]))styles[style]=0;
                  size['total'+key.capitalize()] = size['total'+key.capitalize()]+styles[style];
                  size['computed'+edge.capitalize()] = size['computed'+edge.capitalize()]+styles[style];
               }
               //if width != width (so, padding-left, for instance), then subtract that from the total
               if(style.test(edge) && key!=style && 
                  (style.test('border') || style.test('padding')) && !subtracted.contains(style)) {
                  subtracted.push(style);
                  size['computed'+key.capitalize()] = size['computed'+key.capitalize()]-styles[style];
               }
            });
         });
      });
      if($chk(size.width)) {
         size.width = size.width+this.offsetWidth+size.computedWidth;
         size.totalWidth = size.width + size.totalWidth;
         delete size.computedWidth;
      }
      if($chk(size.height)) {
         size.height = size.height+this.offsetHeight+size.computedHeight;
         size.totalHeight = size.height + size.totalHeight;
         delete size.computedHeight;
      }
      return $extend(styles, size);
   }
});

/*
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();
}


/*
Script: JsonP.js
   Defines JsonP, a class for cross domain javascript via script injection.

License:
   http://clientside.cnet.com/wiki/cnet-libraries#license
*/
var JsonP = new Class({
   Implements: [Options, Events],
   options: {
// onComplete: $empty,
      callBackKey: "callback",
      queryString: "",
      data: {},
      timeout: 5000,
      retries: 0
   },
   initialize: function(url, options){
      this.setOptions(options);
      this.url = this.makeUrl(url).url;
      this.fired = false;
      this.scripts = [];
      this.requests = 0;
      this.triesRemaining = [];
   },
   request: function(url, requestIndex){
      var u = this.makeUrl(url);
      if(!$chk(requestIndex)) {
         requestIndex = this.requests;
         this.requests++;
      }
      if(!$chk(this.triesRemaining[requestIndex])) this.triesRemaining[requestIndex] = this.options.retries;
      var remaining = this.triesRemaining[requestIndex]; //saving bytes
      dbug.log('retrieving by json script method: %s', u.url);
      var dl = (Browser.Engine.trident)?50:0; //for some reason, IE needs a moment here...
      (function(){
         var script = new Element('script', {
            src: u.url, 
            type: 'text/javascript',
            id: 'jsonp_'+u.index+'_'+requestIndex
         });
         this.fired = true;
         this.addEvent('onComplete', function(){
            try {script.dispose();}catch(e){}
         }.bind(this));
         script.inject(document.head);

         if(remaining) {
            (function(){
               this.triesRemaining[requestIndex] = remaining - 1;
               if(script.getParent() && remaining) {
                  dbug.log('removing script (%o) and retrying: try: %s, remaining: %s', requestIndex, remaining);
                  script.dispose();
                  this.request(url, requestIndex);
               }
            }).delay(this.options.timeout, this);
         }
      }.bind(this)).delay(dl);
      return this;
   },
   makeUrl: function(url){
      var index;
      if (JsonP.requestors.contains(this)) {
         index = JsonP.requestors.indexOf(this);
      } else {
         index = JsonP.requestors.push(this) - 1;
         JsonP.requestors['request_'+index] = this;
      }
      if(url) {
         var separator = (url.test('\\?'))?'&':'?';
         var jurl = url + separator + this.options.callBackKey + "=JsonP.requestors.request_" +
            index+".handleResults";
         if(this.options.queryString) jurl += "&"+this.options.queryString;
         jurl += "&"+Hash.toQueryString(this.options.data);
      } else var jurl = this.url;
      return {url: jurl, index: index};
   },
   handleResults: function(data){
      dbug.log('jsonp received: ', data);
      this.fireEvent('onComplete', [data, this]);
   }
});
JsonP.requestors = [];


/*
Script: Element.Position.js
   Extends the Element native object to include methods useful positioning elements relative to others.

License:
   http://clientside.cnet.com/wiki/cnet-libraries#license
*/

Element.implement({

   setPosition: function(options){
      $each(options||{}, function(v, k){ if (!$defined(v)) delete options[k]; });
      options = $merge({
         relativeTo: document.body,
         position: {
            x: 'center', //left, center, right
            y: 'center' //top, center, bottom
         },
         edge: false,
         offset: {x:0,y:0},
         returnPos: false,
         relFixedPosition: false,
         ignoreMargins: false
      }, options);
      //compute the offset of the parent positioned element if this element is in one
      var parentOffset = {x: 0, y: 0};
      var parentPositioned = false;
      var putItBack = this.expose();
    /* dollar around getOffsetParent should not be necessary, but as it does not return 
     * a mootools extended element in IE, an error occurs on the call to expose. See:
       * http://mootools.lighthouseapp.com/projects/2706/tickets/333-element-getoffsetparent-inconsistency-between-ie-and-other-browsers */
      var offsetParent = $(this.getOffsetParent());
      putItBack();
      if(offsetParent && offsetParent != this.getDocument().body) {
         var putItBack = offsetParent.expose();
         parentOffset = offsetParent.getPosition();
         putItBack();
         parentPositioned = true;
         options.offset.x = options.offset.x - parentOffset.x;
         options.offset.y = options.offset.y - parentOffset.y;
      }
      //upperRight, bottomRight, centerRight, upperLeft, bottomLeft, centerLeft
      //topRight, topLeft, centerTop, centerBottom, center
      function fixValue(option) {
         if($type(option) != "string") return option;
         option = option.toLowerCase();
         var val = {};
         if(option.test('left')) val.x = 'left';
         else if(option.test('right')) val.x = 'right';
         else val.x = 'center';

         if(option.test('upper')||option.test('top')) val.y = 'top';
         else if (option.test('bottom')) val.y = 'bottom';
         else val.y = 'center';
         return val;
      };
      options.edge = fixValue(options.edge);
      options.position = fixValue(options.position);
      if(!options.edge) {
         if(options.position.x == 'center' && options.position.y == 'center') options.edge = {x:'center',y:'center'};
         else options.edge = {x:'left',y:'top'};
      }
      
      this.setStyle('position', 'absolute');
      var rel = $(options.relativeTo) || document.body;
      var top = (rel == document.body)?window.getScroll().y:rel.getPosition().y;
      var left = (rel == document.body)?window.getScroll().x:rel.getPosition().x;
      
      if (top < 0) top = 0;
      if (left < 0) left = 0;
      var dim = this.getDimensions({computeSize: true, styles:['padding', 'border','margin']});
      if (options.ignoreMargins) {
         options.offset.x = options.offset.x - dim['margin-left'];
         options.offset.y = options.offset.y - dim['margin-top'];
      }
      var pos = {};
      var prefY = options.offset.y.toInt();
      var prefX = options.offset.x.toInt();
      switch(options.position.x) {
         case 'left':
            pos.x = left + prefX;
            break;
         case 'right':
            pos.x = left + prefX + rel.offsetWidth;
            break;
         default: //center
            pos.x = left + (((rel == document.body)?window.getSize().x:rel.offsetWidth)/2) + prefX;
            break;
      };
      switch(options.position.y) {
         case 'top':
            pos.y = top + prefY;
            break;
         case 'bottom':
            pos.y = top + prefY + rel.offsetHeight;
            break;
         default: //center
            pos.y = top + (((rel == document.body)?window.getSize().y:rel.offsetHeight)/2) + prefY;
            break;
      };
      
      if(options.edge){
         var edgeOffset = {};
         
         switch(options.edge.x) {
            case 'left':
               edgeOffset.x = 0;
               break;
            case 'right':
               edgeOffset.x = -dim.x-dim.computedRight-dim.computedLeft;
               break;
            default: //center
               edgeOffset.x = -(dim.x/2);
               break;
         };
         switch(options.edge.y) {
            case 'top':
               edgeOffset.y = 0;
               break;
            case 'bottom':
               edgeOffset.y = -dim.y-dim.computedTop-dim.computedBottom;
               break;
            default: //center
               edgeOffset.y = -(dim.y/2);
               break;
         };
         pos.x = pos.x+edgeOffset.x;
         pos.y = pos.y+edgeOffset.y;
      }
      pos = {
         left: ((pos.x >= 0 || parentPositioned)?pos.x:0).toInt(),
         top: ((pos.y >= 0 || parentPositioned)?pos.y:0).toInt()
      };
      if(rel.getStyle('position') == "fixed"||options.relFixedPosition) {
         pos.top = pos.top.toInt() + window.getScroll().y;
         pos.left = pos.left.toInt() + window.getScroll().x;
      }

      if(options.returnPos) return pos;
      else this.setStyles(pos);
      return this;
   }
});



/*
 * function Bebo.util.Namespace() { var path = "";
 * $A(arguments).each(function(item,index) { path += (path.length>0?".":"") +
 * item; }); try {return eval(path);} catch(err) {return null;} }
 */

/**
 * see binding mutator http://blog.kassens.net/binds-class-mutator
 */
Class.Mutators.Binds = function(self, methods) {
	$splat(methods).each( function(method) {
		var fn = self[method];
		self[method] = function() {
			return fn.apply(self, arguments);
		};
	});
};

//MediaGlow v1 beacoN v7
var bN={v:7,h:['www.bebo.com','apps.bebo.com','testtrunk.bebo.com','testbranch.bebo.com','apps.testtrunk.bebo.com','apps.testbranch.bebo.com'],b:"",w:100,t:document.title,r:document.referrer,ae:function(A,B,C){if(A.addEventListener){A.addEventListener(B,C,false)}else{if(A.attachEvent){A.attachEvent("on"+B,C)}}},d:new Date(),init:function(){var I=window,F=bN.h.toString(),G=I.location.hostname,E=new RegExp(G+"![0-9]+"),H=F.match(E),A="undefined",J=(typeof bN_cfg!=A)?bN_cfg:A;if(J!=A){if(typeof J.h!=A){F+=J.h.toString()}if(typeof J.b!=A){bN.b=J.b}if(typeof J.p!=A){var C=J.p,D,B;for(D=0,B=C.length;D<B;D++){bN.set(C[D][0],C[D][1],(typeof C[D][2]!=A)?C[D][2]:0)}}if(typeof J.ls!=A){bN.ls=J.ls}if(typeof J.w!=A){bN.w=J.w}}if(I.__bNi){return }if(F.indexOf(G)==-1){return }H=(H)?parseInt(H[0].replace((G+"!"),"")):0;if(Math.floor(Math.random()*H)!=0){return }bN.ae(I,"load",bN.load);bN.ae(document,"click",bN.click);bN.img("vanity/","");I.__bNi=1},f:1,wait:function(){var A,B=new Date();do{A=new Date();if(bN.f){return }}while(A-B<bN.w)},img:function(G,D){var C,A,H=new Image(),F=encodeURIComponent;C=new Date();A="?ts="+C.getTime()+"&h="+F(window.location.hostname)+"&v="+bN.v+"&t="+F(bN.t)+"&r="+F(bN.r)+"&l="+bN.l+"&ms="+(C-bN.d);H.onload=function(){bN.f=1};bN.f=0;if(!bN.b){var B=window.location.hostname.split("."),E=B.length-1;B="b."+B[E-1]+"."+B[E];bN.b=B}H.src="http://"+bN.b+"/"+G+A+D+bN.g+bN.i;bN.i="";if(D&&D.indexOf(F(window.location.href.replace(/#.*/,"")+"#"))==-1&&D.indexOf("javascript%3A")==-1&&D.indexOf("&tag=")==-1){if(!document.all){bN.wait()}}},l:0,ls:0,load:function(){var A=new Date();bN.l=A-bN.d;if(Math.floor(Math.random()*bN.ls)!=0){return }bN.ping("load")},p:[],ping:function(B,A){var C=encodeURIComponent;if(typeof bN.p[B]!="undefined"){clearInterval(bN.p[B])}if(typeof A=="number"){if(A>0){A=A*1000;bN.p[B]=setInterval("bN.img('ping', '&nm="+C(B)+"')",A)}else{return }}bN.img("ping","&nm="+C(B))},click:function(B){var K=window,I=document,M=B||K.event,E=M.srcElement||M.target,O,C,D,L,A,N="",F="",J=0,H=0,G=encodeURIComponent;do{O=E.nodeName;if(E.className.indexOf("bN")!=-1){N+="&tag="+O}if(O=="IMG"){N+="&img="+G(E.src);D=E.alt;if(D){N+="&alt="+G(D)}}if(O=="A"){A=E.href;if(A){N+="&ah="+G(A)}else{return }L=E.innerHTML.replace(/<[^>]*>/g,"");if(L){N+="&at="+G(L)}}if(O=="INPUT"){C=E.type;if(C=="button"||C=="submit"||C=="image"){N+="&btn="+G(E.value)}}F+=(E.id)?E.id+"+":"";E=E.parentNode}while(O!="HTML");if(N!=""){if(M.pageX||M.pageY){J=M.pageX;H=M.pageY}else{if(M.clientX||M.clientY){J=M.clientX+I.body.scrollLeft+I.documentElement.scrollLeft;H=M.clientY+I.body.scrollTop+I.documentElement.scrollTop}}N+="&cx="+J+"&cy="+H;if(F){N+="&id="+G(F.slice(0,-1))}bN.img("click",N)}},g:"",i:"",set:function(C,F,B){var D=encodeURIComponent,A=B?bN.i:bN.g,E=new RegExp("&"+D(C)+"=[^&]*"),G="&"+D(C)+"="+D(F);if(E.test(A)){if(F){A=A.replace(E,G)}else{A=A.replace(E,"")}}else{A+=G}if(B){bN.i=A}else{bN.g=A}}};bN.init()

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 $try(function(){
         var root = '<root>' + text + '</root>', doc;
         if (Browser.Engine.trident){
            doc = new ActiveXObject('Microsoft.XMLDOM');
            doc.async = false;
            doc.loadXML(root);
         } else {
            doc = new DOMParser().parseFromString(root, 'text/xml');
         }
         root = doc.getElementsByTagName('root')[0];
         for (var i = 0, k = root.childNodes.length; i < k; i++){
            var child = Element.clone(root.childNodes[i], true, true);
            if (child) {
                container.grab(child);
            }
         }
         return container;
      }) || container.set('html', text);*/
      
      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.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.stop(); // we might want to remove this if we want to support
                  // foreign links
      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.mouseLeave.bindWithEvent(this));
      }
   },

   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.removeEvents('mouseleave');
   }
});

/**
 * 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;

		switch (event.key) {
		case 'backspace':
			while (e.rows > this.startingRows
					&& e.getScrollSize().y < e.getSize().y) {
				e.rows--;
			}
		default:
			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') + '/images/pix.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();

		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();
		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 btn' });
				this.cancel.set('html', '<input class="button" type="button" value="'+$I.transf("Cancel")+'"/>');
				this.ok = new Element('span' ,{'class': 'button-wrapper btn'});
				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('h1');
				} else if (this.options.display == 'inline') {

				}
			},

			loading : function() {
				this.content
						.set(
								'html',
								'<img src="' + $V('CDN', 'prefix') + '/images/pix.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();

				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();
				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 :'/images/pix.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', // possible values: 'button', 'button small',
							// 'cancel', 'cancel small'
		'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 : {
		//element 
		title :"Title",
		className :'popup',
		throbber :'/images/pix.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...")})
      );

      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);
	  if (this.options.position == 'top') {
	     elementTop = 80;
      } else {
	     // todo: convert to 1/3 top
	     elementTop = parseInt(window.getHeight() / 3 - eleSize.y / 2);
	     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 :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 :15, // pixels
		className :'bebobox',
		overlayAll :false
	// 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)) {
			new Element('h1', {
				'text' :this.options.title
			}).inject(this.element, 'top');
		}

		if (this.options.showClose) {
			this.closeLink = new Element('img', {
				'src' :'http://s.bebo.com/img/icon_notattending.gif',
				'styles' : {
					'position' :'absolute',
					'top' :-5,
					'right' :-5,
					'z-index' :'9999',
					'cursor' :'pointer'
				}
			});
			this.closeLink.addEvent('click', function() {
				this.close()
			}.bind(this));
			this.closeLink.inject(this.element);
		}
	},

	buildBackground : function() {
		var bg = new Element('div', {
			'id' :'bebobox_bg',
			'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();
	}

	// display
	this.element.setStyle('display', 'block');
	this.element.setOpacity(1);

	// hide all ads
	$$('div.advertisement').setStyle('visibility', 'hidden');

	var eleSize = this.element.getSize();

	// center
	elementLeft = parseInt(window.getWidth() / 2 - eleSize.x / 2);
	if (this.options.position == 'top') {
		elementTop = 80;
	} else {
		// todo: convert to 1/3 top
	elementTop = parseInt(window.getHeight() / 3 - eleSize.y / 2);
	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.4
});

// show and position close button
this.visible = true;
},

show : function() {
this.open();
},

close : function() {
this.bg.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 :this.close,

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

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',

		onCancel : function() {
			this.close();
			this.fireEvent('close');
		}
	},

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

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

		// buttons
   	var buttons = new Element('p', {
   		'class' :'button-row'
   	});
   	this.ok = new Element('img', {
   		'src' :'/img/story/ok.gif'
   	});
   	this.cancel = new Element('img', {
   		'src' :'/img/story/cancel.gif'
   	});
   	buttons.adopt(this.ok);
   	buttons.adopt(this.cancel);
   	container.adopt(buttons);
   
   	this.options.element = container;
   
   	this.ok.addEvent('click', function() {
   		this.fireEvent('ok', this);
   	}.bind(this));
   
   	this.cancel.addEvent('click', function() {
   		this.fireEvent('cancel', this);
   	}.bind(this));
   
   	this.parent(this.options);
   }
})

/**
 * 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) {
		var text = this.options.text;

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

		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);

				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');

				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');
	}
};

/* jason - for app icons on profile_jsp */
var loadTips = function() {
	window.addEvent('load', function(e) {
		new Tips($$('.fixed_tip'), {
			showDelay :100,
			hideDelay :100,
			fixed :true
		});
	});
};
/* end fixed tips */

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 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>";
			if (id.contains('app')) {
				var content_url = "/c/apps/get_app_content?ProfileMemberId="
						+ profileMemberId + "&AppId=" + id;
				if (set !== false) {
					url += "&HideModule=N";
					var transaction = YAHOO.util.Connect.asyncRequest('GET',
							url, null, null);
				}
			} else {
				var content_url = url += "&GetContent=Y&HideModule=N";
			}
			new Request.HTML( {
				url :content_url,
				method :'GET',
				update :p,
				evalScripts :true
			}).send();
		} else {
			if (set !== false) {
				url += "&HideModule=N";
				var 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";
		var 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');

		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
				if (curNode.nodeType != 3) { // node type 3 is #text
					var 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 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 display(elementName, display) {
	var elem = document.getElementById(elementName);

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

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) { // aplatti: hack for QA WebTest
		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();
		}
	}
}
/*
 * if (window.addEventListener) { // W3C document.addEventListener("click",
 * _hideFlagsOnDocumentClick, false); } else if (window.attachEvent) { //
 * Microsoft document.attachEvent("onclick", _hideFlagsOnDocumentClick); }
 */

/* 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 { // if (navigator.appName.indexOf("Microsoft Internet")!=-1)
		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 = "http://s.bebo.com/music_player_button.swf?v=3";
			swfName = "/music_player_button.swf?v=4";
			// vars = "songurl="+vars;
			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.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.removeEvents('mouseleave');
	}
});

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.stop();
      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() {
	new bebo.ui.DropDown(this);
});
YAHOO.util.Event.onContentReady('yahoo-search-form', function() {
	new bebo.ui.GlobalSearchBox(this);
});

$(document).addEvent('endofbody', function(event) {
	$$("ul.lang-selector").each( function(el) {
		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;
	};
}
