/* [file src="base/Portal.js"]
*/
/*	usemedia.com . joes koppers . 11.2007, rev 01.2010
	thnx for reading this code */


/*	7s main Application
*/

function Portal7(layout,lan,link,dev)
{
	var obj = this;

	/*	GWorx
	*/
	this.path = '/gstudio/';
	GW.init(function(id,error,details,tagname){
		obj.gwNegRsp(id,error,details,tagname)
	},30,'/gstudio');
	
	
	/*	settings, defaults
	*/
	this.name = '7scenes';
	this.release = 'copenhagen';
	this.version = '3.0';
	this.mode = (dev)? 'test':'production';
	this.server = (location.host=='7scenes.com' || location.host=='www.7scenes.com')? 'prod':'test';
	
	//*.7scenes.com google api key
	this.Gkey = 'ABQIAAAA6wAMqFuY8aYUX67TtQkcKRTeOqKVykba4WR2nhx8HxyL1B1oEhT1ELlcTBbYK5PR1BgrsQ5lIdOrmw';
	if (window.location.host.indexOf('7s-c')!=-1)
	{
		//local development key
		this.Gkey = 'ABQIAAAA6wAMqFuY8aYUX67TtQkcKRQ94lZtj2-buaeBZetsSPQHYDPhPxTHQzQ6-SiL4KL23xXAEl4Eqqo_eA';
	}
	
	this.disable_live_polling = false; 	//do not poll for live scenes/traces (development feature)
	this.scene_activity_check = 20;		//seconds, polling interval for scene activity
	this.scene_traces_check = 20;		//seconds, polling interval for live traces
	if (this.server=='prod') this.disable_live_polling = false; //so we can't forget to enable it..

	this.enabled = 'base'; //set of code loaded: base, scenes or user
	this.state = 'portal'; //state of interface: portal, scene (playback, live, play), direct, directplaces
	this.scenestates = { 1:'draft', 2:'public', 3:'closed' };
	this.eventstates = { 1:'scheduled', 2:'running', 3:'done' };
	
	this.login = { 
		autologin:false,
		set_autologin:true,
		roles: { 
			admin:new Object(),
			director:new Object(),
			loaded:false
		}
	};

	this.utils();
	
	
	/*	config
	*/
	this.initialView = this.view = layout;	//home (50%), page (collapsed, fixed) or scenes (full)
	this.language = lan;
	if (link)
	{
		var p = link.split('/');
		var type = p.length>1 ? p[0]:'scene'; //defaults to scene, so 7scenes.com/sceneid is also a valid scene link
		var id = p.length>1 ? p[1]:p[0];
		this.link = { type:type, id:id, path:link };
		
		dbg.msg('link=',dbg.obj(this.link));
	}
	this.setDefaults();


	/*	initialize display and login
	*/
	this.initGui();
	this.autoLogin();
}

Portal7.prototype.setDefaults = function()
{
 	/*	template defaults //->move to external later (store in db?)
 	*/
 	this.template = {
 		placetypes: ['task','text','image','audio','video','reward','trade'],
 		placeNames: {
 			task:'task',
 			text:'note',
 			image:'photo',
 			audio:'sound',
 			video:'video',
 			reward:'reward',
 			trade:'trade',
 			'task-multichoice':'quiz task',
 			'task-photosubmit':'photo task'
 		},
 		roles: ['role1','role2','role3','role4'],
 		skills: ['skill1','skill2','skill3','skill4'],
 		assignments: ['assignment1','assignment2','assignment3','assignment4'],
 		objects: ['object1','object2','object3','object4'],
 		maxtime: [15,30,45,60,75,90,120,150,180],
 		skillvalues: [10,15,20,25,50,75,100,250],
 		task_scores: [0,10,20,30,40,50,100,150,200,250],
 		teamcolors: ['8b0000','4169E1','006400','DAA520','DA70D6','008B8B']
 	};
}

Portal7.prototype.initGui = function()
{
	/*	init Layout and Gui
	*/
	var obj = this;
	
	Locale7.setDate();

	//cache loading image
	var img = new Image(16,16);
		img.src = 'media/login.gif';
	
	//build main layout
	this.layout = new Layout7(this);
	this.layout.createBaseLayers();
	
	//enable scenes functions (for scenes view or deeplink)
	if (this.layout.layout=='scenes' || this.link)
	{
		this.enable('scenes',function() {
			//deeplink
			if (obj.link) obj.deepLink(obj.link.type);
		});
	}
	
	//get featured scenes
	this.getCoverScenes();
}

Portal7.prototype.enable = function(type,callback)
{
	/*	enable scenes and user functions
	*/
	var obj = this;
	
	switch(type)
	{
		case 'base-user':
			/*	base user functions (profile, myscenes)
			*/
			
			//dbg.msg('Portal: enable base-user, enabled=',this.enabled,', view=',this.view);
			
			if (this.enabled!='scenes' && this.view=='scenes')
			{
				//wait for scenes to be enabled
				return window.setTimeout(function() {
					obj.enable(type);
				},50);
			}
			else if (!this.loggedIn)
			{
				dbg.msg('Portal: loading base-user js..');
			
				//get base-user script
				$.getScript('script/?type=base-user', function() {
					obj.loggedIn();
				})
			}
			else
			{
				obj.loggedIn();
			}
			break;

		case 'scenes':
			/*	scenes layout
			*/
			//get available scenetypes first
			GW.QUERY.queryStore('q-scene-types-info',function(records) {
				
				obj.scenetypes = new Object();
				$.each(records, function(i,rec) {
					obj.scenetypes[ rec.getField('type') ] = { name:rec.getField('name') }
				});
				
				var login = ((obj.login.id || obj.login.autologin) && !obj.login.profile)? true:false;
				
				dbg.msg('Portal: loading scenes js.. ',(login? '(+ base-user)':''));
				dbg.tmr();
				
				$.getScript('script/?type=scenes'+(login? '-base-user':''), function() {
					
					dbg.msg('Portal: enabled=scenes','tmr');
					obj.enabled = 'scenes';

					//scenes collection					
					obj.scenes = new Scenes7(obj);

					//channel cache
					obj.channel = new Object();
		
					//init scenes gui
					obj.layout.addScenesGui();
					obj.layout.createSceneLayers();
					obj.gui.createPortalLists();
					
					obj.getInitialScenes();
					
					if (callback) callback();
				});
			});
			break;
			
		case 'user':
			/*	scenes user layout (direct, play)
			*/
			dbg.tmr();
		
			//load user js
			$.getScript('script/?type=scenes-user', function() {
				
				dbg.msg('Portal: enabled=user','tmr');
				obj.enabled = 'user';

				//init user gui and Direct
				obj.layout.addScenesUserGui();
				obj.layout.createUserLayers();
				obj.addDirect();
				
				if (callback) callback();
			});
			break;
			
		case 'logout':
			/*	disable all user functions
			*/
			this.enabled = this.scenes? 'scenes':'base';
			dbg.msg('Portal: enabled=scenes');

			//reset find layers
			this.find(undefined,true);
			this.myFind(undefined,true);
			
			var m = this.layout.layers['portal'].menubar;
			if (m['manage'].visible)
			{
				if (m.manage.selected) this.manage.show(true);
				m['direct'].show();
				m['manage'].hide();
			}
			
			var b = this.layout.layers['portal'].menubar;
				b['login'].expand(true);
				b['my'].setEnabled(false);
				b['direct'].setEnabled(false);
			
			//remove user layers
 			this.layout.layers.disposeMultiple(['my','profile','direct','manage','invites'])


			if (this.medialib)
			{
				this.medialib.dispose();
				delete this.medialib;
				//delete Portal7.prototype.addMedialib; //->?
			}
			if (this.userlib)
			{
				this.userlib.dispose();
				delete this.userlib;
			}

			//remove extended functionality
/*
			delete this.direct;
			
			//unload extended GUI
			for (var id in this.gui) if (typeof(this.gui[id])=='function') delete this.gui[id];
			
			//unload registered user functionality
			delete Portal7.prototype.extendGui;
			delete Portal7.prototype.addDirect;
			
			delete Scenes7.prototype.enableEditing;
			delete Scenes7.prototype.enablePublishing;
			delete Scenes7.prototype.enablePlay;
*/		
			break;
	}
}

Portal7.prototype.deepLink = function(type,sceneid)
{
	/*	open scene, trace or event, 
		based on friendly url */
		
	dbg.msg('<span style="color:#006699">Portal: deepLink, type=',type);	
	
	var obj = this;
	switch (type)
	{
		case 'scene':
		case 'scenes':
			var id = sceneid || this.link.id;
			if (id=='' || id=='scenes') return dbg.msg('Portal: not a valid deeplink');
 			
 			GW.QUERY.queryStore('q-scenes', function(records) { 
 				if (records.length>0)
 				{
					var r = records[0];
					var foundScene = function() { obj.foundScene(r) };

 					//wait for login roles to be known
 					if (obj.login.id && !obj.login.roles.loaded)
 					{
 						var wait = function() {
 							if (obj.login.roles.loaded) return foundScene();
							window.setTimeout(wait,25);
						};
						wait();
					}
					else
					{
						foundScene();
					}
 				}
 			}, { sceneid:id });
			break;
		
		case 'event':
		case 'trace':
			//get scene id for this trace/event
			var callback = function(type) { obj.deepLink(type) };
			var q = type=='trace'? 'q-trace':'q-round';
			
			GW.QUERY.queryStore(q,function(records) {
				if (records.length>0)
				{
					obj.deepLink('scene',records[0].getField('sceneid'))
				}
			}, { id:this.link.id });
			break;
			
		case 'verify':
			//verify signup
			var p = this.link.path.split('/');
			if (p.length!=3) return dbg.msg('Portal: not a valid deeplink');
			GW.USER.verify(this,p[1],p[2]);
			break;
	}
}

Portal7.prototype.getCoverScenes = function(type,records)
{
	/*	get scenes for coverflow display
	*/
	if (!records)
	{
		if (!type) type = 'featured';

		//update menus
		var c = this.gui.layer.panels['coverflow'];
			c.data('featured').setSelected(type=='featured'? true:false);
			c.data('popular').setSelected(type=='popular'? true:false);
		
		this.gui.coverflow.clear(true);
	
		var obj = this;
		var query = { max:11, minstate:2 };
			query[type] = true;
			
		dbg.tmr();
		//return GW.QUERY.queryStore('q-'+type+'-scenes', function(rsp) { obj.getCoverScenes(type,rsp) },query);
		return GW.QUERY.queryStore('q-scenes', function(rsp) { obj.getCoverScenes(type,rsp) },query);
	}

	dbg.msg('Portal: cover scenes [',type,'], records=',records.length,'tmr');
	
	if (records.length) this.gui.coverflow.update(records)
}


/*	Search
*/
Portal7.prototype.find = function(query,close)
{
	/*	open search layer, enable search gui
	*/

	//update menu, layer
	var m = this.layout.layers['portal'].menubar;
		m['find'].setSelected(close? false:true);
		$(m['find'].div).find('a')
			.css('background-image',close? 'url(media/menu/find.png)':'url(media/menu/find-x.png)');

	//show or hide	
	this.layout[close? 'hideLayers':'showLayers'](['find']);
	if (close) return;
	if (m['login'].expanded) m['login'].expand(false);
	
	this.layout.gui.alignMenuLayer('find');
	
	//enter scenes mode from page-layout
	if (this.view=='page') this.layout.toggle('scenes');

	//hide others
	this.gui.closeMenuLayers('find');
		
	var form = document.forms['searchform'];
		form.query.focus();

	//auto query
	if (query)
	{
		form.query.value = query;
		this.query(undefined,query);
	}
}

Portal7.prototype.query = function(records,q,my)
{
	/*	perform search query
	*/
	var obj = this;
	if (my) var type = $('#my-search-context').find('input[name="context"]:checked').val();

	if (!records)
	{
		/*	reset
		*/
		if (q!=undefined && q.length<2)
		{
			if (my && q.length==0)
			{
				//my: default all scenes (max 100)
				this.gui.updateSearchResult('searching',undefined,my);
				var query = { 
					max:101, 
					userid:this.login.id,
					type:type
				};
				
				dbg.tmr();
				GW.QUERY.queryStore('q-my-scenes', function(rsp) { obj.query(rsp,undefined,my) },query);
			}
			else
			{
				//default: clear list
				this.gui.updateSearchResult('clear',undefined,my);
			}
			return;
		}
		
		/*	query
		*/
		dbg.msg('Portal: execute query, q=',q,my? ', [my]':'');
		this.gui.updateSearchResult('searching',undefined,my);
		
		var query = { max:101, minstate:2, search:escape(q) };
		if (my)
		{
			query.userid = this.login.id;
			query.type = type;
			delete query.minstate;
		}
		else if (this.project && document.forms['searchform'].context.checked)
		{
			query.contextid = this.project.id;
			if (this.project.admin) query.minstate = 1; //project admin can find all scenes within context
		}
	
		dbg.tmr();
		GW.QUERY.queryStore('q-'+(my? 'my-':'')+'scenes', function(rsp) { obj.query(rsp,undefined,my) },query);
		return;
	}
	
	dbg.msg('Portal: query, records=',records.length,'tmr');

	/*	display result
	*/
	this.gui.updateSearchResult(records,undefined,my);
}

Portal7.prototype.foundScene = function(record,my)
{
	/*	open a scene from list record
	*/
	if (this.view!='scenes')
	{
		var obj = this;
		return this.layout.toggle('scenes', function() {
			obj.foundScene(record,my);
		});
	}
	
	dbg.msg('Portal: foundScene, id=',record.getField('id'),my? ', my=true':'');
	
	if (this.scene) this.scene.close();
	this.scenes.clear();

	var rec = record;
	var id = rec.getField('id');
	
	//check access rights, draft scenes can only be viewed by owner or admin
	var state = rec.getField('state');
	var admin = rec.getField('admin');
	var user = rec.getField('user');
	var enabled = (user==this.login.loginname || admin==this.login.loginname || this.login.role==0 || my);
	if (state<2 && !enabled)
	{
		dbg.msg('Portal: foundScene, draft scene view not allowed');
		return;
	}
		
	this.scenes.create( {
		id:id,
	
		name:rec.getField('name'),
		type:rec.getField('type'),
		state:state,

		icon:rec.getField('sceneiconid')? {
			id:rec.getField('sceneiconid'),
			scale:rec.getField('scale'),
			offsetx:rec.getField('offsetx'),
			offsety:rec.getField('offsety')
		}:undefined,
		
		description:rec.getField('description'),
		
		user:user,
		admin:admin,
		context:rec.getField('contextid'),
		
		//eventcount:rec.getField('eventcount'),
		creationdate:rec.getField('creationdate'),
		modificationdate:rec.getField('modificationdate')
	} );
	
	this.scenes[id].enable();
	this.scenes[id].open();
}


/*	Portal features
*/
Portal7.prototype.openDirect = function(id)
{
	/*	enter Direct
	*/
	if (this.enabled!='user')
	{
		var obj = this;
		if (this.enabled!='scenes')
		{
			return this.layout.toggle('scenes',function() { obj.openDirect(id) });
		}
	
		return this.enable('user',function() { obj.openDirect(id) });
	}

	if (this.view!='scenes') this.layout.toggle('scenes');
	this.direct.direct(id);
}

Portal7.prototype.help = function(record,r)
{
	if (typeof(record)!='object')
	{
		dbg.msg('Portal: help(',record,')')

	
		//get help text
		var obj = this;
		GW.QUERY.queryStore('q-text-by-name',function(rsp) { obj.help(rsp,record) },'name',record+'_help','lang',this.language.toUpperCase());
		return;
	}
	
	//set help pane contents and show
	if (record[0]) var help = record[0].getField('content');
	else var help = 'help file missing ('+r+'_help, language:'+this.language+')';
	this.layout.panes['help'].setContent(help);
	this.layout.panes.show('help');
}


/*	verification and authentication
*/
Portal7.prototype.verifyRsp = function(rsp)
{
	/*	autologin after successful verification
	*/
	var login = this.parseXML(rsp.firstChild);

	this.login.loginname = login.name;
	this.login.password = login.password;
	
	this.setAutoLogin(false); //reset any previous autologin
	this.login.set_autologin = false; //do not set cookie, as we don't have the regular password
	
	var obj = this;
	this.login.action = function() {
		obj.login.profile.show();
		alert(Locale7.get('gui','verified'));
	}

	this.doLogin(true,true);
}

Portal7.prototype.verifyNegRsp = function(errorId,error,details,tagname)
{
	dbg.msg('gwNegrsp: errorid=',errorId,', error=',error,', details=',details);
	alert('Error!\n\nCould not verify signup:\n'+details);
}

Portal7.prototype.autoLogin = function()
{
	/*	read and parse autologin cookie
	*/
	if (this.link && this.link.type=='verify') return;
	
	var autologin = this.utils.readCookie('autologin');
	dbg.msg('Portal: autologin=',autologin);

	if (autologin && autologin!='false')
	{
		var data = autologin.split('/');
		var d = this.utils.encrypt(data[0],true).split(',');
		this.login.loginname = d[0];
		this.login.password = d[1];
		this.login.language = data[1] || 'EN';//Gui defaults to english
		this.login.autologin = true;
		
		this.doLogin(true);
	}
}

Portal7.prototype.setAutoLogin = function(s)
{
	/*	(re)set autologin cookie
	*/
	if (s=='toggle')
	{
		this.login.set_autologin = !this.login.set_autologin;
		//focus login field
		document.forms['loginform'].login.focus();
	}
	else
	{
		dbg.msg('Portal: set autologin=',s);
	
		//(re)set cookie
		if (!s) this.login.autologin = false;
		var days = (!s)? -1:14; //cookie expires 2 weeks from now
		var value = (!s)? false:utils.encrypt(this.login.loginname+','+this.login.password)+'/'+this.login.profile.language;	
		var d = new Date();
		d.setTime(d.getTime()+(days*24*60*60*1000));
		var expires = '; expires='+d.toGMTString();
		document.cookie = 'autologin='+value+expires+'; path=/';
	}
}

Portal7.prototype.doLogin = function(autologin,verify)
{
	dbg.msg('Portal: logging in..',autologin? ' (autologin)':'');

	//get form values
	if (!autologin)
	{
		this.login.loginname = document.forms['loginform'].login.value;
		this.login.password = document.forms['loginform'].password.value;
	}
	
	//validate
	if (this.login.loginname=='' || this.login.password=='') 
	{
		alert(Locale7.get('error','no_login_input'));
		return false;
	}

	//display wait anim
	this.layout.layers['portal'].menubar['login'].setContent(this.gui.create('logging_in'));
	
	//send login request
	var obj = this;
	GW.login(this,this.login.loginname,this.login.password,verify);
	
	return false; //prevent form from submitting
}

Portal7.prototype.loginRsp = function(rsp)
{
	this.login.agentkey = rsp.getAttribute('agentkey');
	this.login.userid  = rsp.getAttribute('userid');
	this.login.role = rsp.getAttribute('role');
	
	this.login.id = this.login.userid; //enables user Gui
	
	dbg.msg('Portal: login succes, id=',this.login.userid,', name=',this.login.loginname,', key=',this.login.agentkey);
	dbg.msg('* we are now logged in *');


	/*	update/enable Gui
	*/

	//reset serach results
	this.find(undefined,true);
	if (this.myFind) this.myFind(undefined,true);
	
	//menus
	var b = this.layout.layers['portal'].menubar;
		b['login'].expand(false);
		b['my'].setEnabled(true);
		//b['direct'].setEnabled(true);
	
	
	//enter scenes view
	if (!this.login.autologin && (this.view=='home' || this.view=='page'))
	{
		this.layout.toggle('scenes');
	}
	
	//current scene?
	if (this.scene)
	{
		this.scene.enable();
		this.scene.open();
	}

	//set autologin state //->MOVED to get-profile
	//if (!this.login.autologin && this.login.set_autologin) this.setAutoLogin(true);

	//base user functions
	this.enable('base-user');
}

Portal7.prototype.loginNegRsp = function(errorId,error,details,tagname)
{
	dbg.msg('login error: id=',errorId,', err=',error,', details=',details);

	switch (errorId)
	{
		case '4100':
		case '4101':
		default:
			alert(Locale7.get('error','login').replace('$1',details));
			delete this.login.id;
			delete this.login.loginname;
			delete this.login.password;
			break;
	}
	
	//reset login form
	var obj = this.layout.layers['portal'].menubar['login'];
	var delayed = function() { obj.expand(1) };
	
	window.setTimeout(delayed,200);
}

Portal7.prototype.logout = function()
{
	dbg.msg('Portal: logging out..');
	
	if (this.scene) 
	{
		if (!this.scene.close(false,true)) return;
	}
	
	//clear login data
	delete this.login;
	this.login = {
		autologin: false,
		set_autologin: true,
		roles: {
			admin: new Object(),
			director:new Object(),
			loaded:false
		}
	};

	this.setAutoLogin(false);
	this.enable('logout');
	

	GW.logout();

	
	/*	we are now logged out
	*/

	//this.setUserEnabled(false);
}

Portal7.prototype.lostPassword = function()
{
	/*	retrieve lost password (via drupal)
	*/
	var host = window.location.host;
	if (host=='7s-c') host = 'dev.7scenes.com'; //local development
	//return window.location = 'http://cms.'+host+'/gwsession/'+GW.agentKey+'/gworx/user/reset';
	return window.location = 'http://cms.'+host+'/reset-password';
}


/*	GWorx generic negative response handler
*/
Portal7.prototype.gwNegRsp = function(errorId,error,details)
{
	dbg.msg('gwNegrsp: errorid=',errorId,', error=',error,', details=',details);

	// 4220 - Exceeded public scenes
	// 4221 - Exceeded draft scenes
	// 4222 - Exceeded number of directors	
	
	if (errorId=='6007')
	{
		//insufficient rights, generic alert
		alert('Error!\n\nthis action is not allowed for your login');
	}
}


/*	utilities
*/
Portal7.prototype.utils = function()
{
	this.utils = {

		readCookie: function(name) { //from www.quirksmode.org
			var nameEQ = name + "=";
			var ca = document.cookie.split(';');
			for (var i=0; i<ca.length; i++)
			{
				var c = ca[i];
				while (c.charAt(0)==' ') c = c.substring(1,c.length);
				if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
			}
			return false;
		},
		encrypt: function(str,decrypt) {
		
			/*	simple (not secure!) hide cleartext function
			*/
			var result = '';
			if (decrypt)
			{
				for (var i=0; i<str.length; i+=2)
				{
					var n = parseInt(str.substr(i,[2])) + 23;
					n = unescape('%' + n.toString(16));
					result+= n;
				}
				result = unescape(result);
			}
			else
			{
				for (var i=0; i<str.length; i++) result+= str.charCodeAt(i) - 23;
			}
			return result;
		}
	};
}

Portal7.prototype.stripTags = function(str)
{
	/*	(basic) html tag removal for strings
	*/
	return str.replace(/<\/?[^>]+>/gi,'');
}

Portal7.prototype.parseXML = function(elm)
{
	/*	parse XML element to JSON
		conventions:	arrays are defined as <elmlist><elm></elm></elmlist>  */
		
	if (!elm || !elm.attributes) return;

	if (elm.tagName && elm.tagName.indexOf('list')!=-1)
	{
		/*	list
		*/
		var elms = elm.getElementsByTagName(elm.tagName.substring(0,elm.tagName.indexOf('list')));

		var list = new Array();
		for (var i=0; i<elms.length; i++)
		{
			list.push(this.parseXML(elms[i]));
		}
		return list;
	}
	else if (elm.childNodes.length==1 && elm.firstChild.nodeType==3)
	{
		/*	element with text value
		*/
		if (elm.firstChild.nodeValue=='true') return true;
		if (elm.firstChild.nodeValue=='false') return false;
		return elm.firstChild.nodeValue;
	}
	else if (elm.childNodes.length==0 && elm.attributes.length==0)
	{
		/*	empty element
		*/
		return null;
	}
	else
	{
		/*	attributes and/or nested elements, recursive parsing
		*/
		var object = new Object();

		for (var i=0; i<elm.attributes.length; i++)
		{
			object[elm.attributes.item(i).name] = elm.attributes.item(i).value;
		}

		for (var i=0; i<elm.childNodes.length; i++)
		{
			object[elm.childNodes[i].tagName] = this.parseXML(elm.childNodes[i]);
		}

		return object;
	}
}

/* [file src="base/Layout.js"]
*/
/*	usemedia.com . joes koppers . 11.2007, rev 01.2010
	thnx for reading this code */


/*	7s base Layout and Layers
*/

function Layout7(portal)
{
	/*	main layout
	*/
	this.portal = portal; //ref to parent
	this.layout = portal.view;
	this.cssfilter = (typeof(document.body.style.filter)=='string')? true:false; //means IE
	
	this.div = $('#layout')[0];
	
	this.fullscreen = false;
	this.resize(1); //set initial dimensions
	
	//base gui
	this.addGui(portal);
	this.portal.gui = this.gui; //->backwards compatibility, remove after cleanup

	this.addLayers(portal);
	
	//window resize event
	var obj = this;
	$(window).resize(function(){ obj.resize() });
}

Layout7.prototype.getCSS = function(type)
{
	/*	load additional css
	*/
	var l = document.createElement('link');
		l.rel = 'stylesheet'
		l.type = 'text/css';
		l.href = 'style/'+type+'.css';

	document.getElementsByTagName('head')[0].appendChild(l);
}

Layout7.prototype.toggle = function(mode,callback)
{
	/*	transition to and from scenes layout
	*/
	dbg.msg('Layout: toggle(',mode,')');

	var obj = this;
	this.portal.view = this.layout = mode;
	
	if (this.portal.scene)
	{
		//show/hide scene layers
		$('#scene')[mode=='scenes'? 'show':'hide']();
	}
	
	//show/hide portal scenes panels
	$('#layer-panel-channel,#layer-panel-tag')[mode=='scenes'? 'show':'hide']();
	
	//slide callback
	var layer = this.layers['portal'];
		layer.slideCallback = function() {
			var l = this.parent.layout;

			$('#page')
				.removeClass('home '+(l=='page'? 'scenes':'page'))
				.addClass(l);
				
			$('#page-no-scroll').css('overflow',l=='page'? 'visible':'hidden');
	
			if (l=='scenes') this.menubar.about.show();
			this.update();
			
			if (obj.layout=='scenes')
			{
				if (obj.portal.enabled=='base') this.portal.enable('scenes',callback);
				else if (callback) callback();
			}
		}

	//slide
	delete layer.align;
	$(layer.content)[mode=='page'? 'hide':'show']();
	
	var ty = this.portal.initialView=='home'? Math.max(620,this.h)/2:this.h-50;
	//var ty = this.h - 50;
	layer.slideTo(layer.x,mode=='scenes'? layer.oy:ty);
}

Layout7.prototype.resize = function()
{
	/*	current window dimensions
	*/
	this.w = $(window).width();
	this.h = $(window).height();
	
	if (this.layers) this.update();

	//development
	if (typeof(dbg)=='object') dbg.moveTo(20,this.h-dbg.h-10); //align debugger at left bottom
}

Layout7.prototype.update = function()
{	
	/* resize all layers in layout
	*/
	for (var id in this.layers)
	{
		if (typeof(this.layers[id])=='object')
		{
			this.layers[id].update();
			if (this.layers[id].extendUpdate) this.layers[id].extendUpdate();
		}
	}
}

Layout7.prototype.createBaseLayers = function()
{
	/*	create portal layer ("scenes") and menus
	*/
			
	var obj = this;
	dbg.msg('Layout: creating Portal layers..');

	/*	portal (scenes)
	*/
	var layer = this.layers.create({
		id:'portal',
		x:0, y:4, r:0, b:0,
		z:0,
		bcolor:'#096393',
		//bcolor:'rgba(0,0,0,0.1)',
		gradient:'bg-scenes-layer.jpg',
		hcolor:'#ffffff', hcolor2:'#f2f2f2',
		shadow:true,
		title:'<img src="media/layer-label-scenes.png" class="layer-label">',
		parent:this
	});
	
	this.gui.layer = layer;
	layer.slide_speed = 0.22;
	
	//add 'home' click
	$('#portal')
		.find('.header, .titlebar')
		.css('cursor','pointer')
		.attr('title',Locale7.get('gui','back_to_scenes'))
		.click(function(e) {
			if (e.shiftKey && typeof(dbg)=='object') 
			{	
				//development feature, shift-click to enable debugger
				dbg.setEnabled(true);
				return;
			}
			if (obj.layout!='scenes') return obj.toggle('scenes');
			if (obj.portal.scene) obj.portal.scene.close();
		});

	//override default layer resize
	layer.update = function(p,sliding)
	{
		/*	update layer position and scale
		*/
		if (p)
		{
			this.setPosition(p.x,p.y);
			this.setSize(p.h,p.w);
		}
		else
		{
			var x,y;
			
			//portal layer: keep centered and selected view (home, page or scenes)
			if (!obj.fullscreen && !sliding)
			{
				x = $('#page').offset().left;
				this.r = x;

				if (obj.layout=='page')
				{
					//collapsed view
					$(this.div).css('position','fixed');
					this.align = { b:50 };
				}
				else
				{
					delete this.align;
					$(this.div).css('position','absolute');
				}
				if (obj.layout=='home')
				{
					//50% view
					y = $('#page').height();
				}
			}
			
			if (this.align && this.align.b)
			{
				var y = this.parent.h - this.align.b;
			}
			
			this.setPosition(x,y);
			this.setSize();
		}
		
		//update layer panels
// 		var w = Math.floor($(this.div).width());
// 		if (w%2) w++; //we need an even number for panel widths
// 		$('#layer-panel-featured').css('width',w-98);
		
		if (obj.layout=='scenes' && !sliding)
		{
			if (this.panels)
			{
				//channel and tag panels, resize to fit exact amount of rows
				var l = this;
				$.each(['channel','tag'], function(i,v) {
					var panel = l.panels[v];
					if (!panel) return true;
					//available height and rows
					var d = l.h - panel.position().top - 113;
					var rows = Math.max(2,Math.floor((d-25-7)/105));
					//resize
					panel.find('.panel-body').css('height',(rows * 105) + 25 + 8);
					//update list
					if (panel.data('list')) panel.data('list').setSize();
				});
			}
		}
	}

	$(layer.content)
		.addClass('portal')
		.css('overflow','visible')
		[this.layout=='page'? 'hide':'show']();
		
	layer.update();
	
	
	/*	portal layer menus
	*/
	var login = layer.addMenu({
		id:'login',
		w:90,
		color:'#aa0000', color2:'#890000',
		selected:{ c:'#890000', c2:'#7b0000' },
		content:'<a href="javascript://login" style="width:65px; background-image:url(media/menu/login.png)"></a>'
	});
	//add login input interaction
	this.gui.enableLoginMenu();
	
	var direct = layer.addMenu({
		id:'direct',
		w:80,
		color:'#aa0000', color2:'#890000',
		enabled:false,
		content:'<a href="javascript://direct" style="width:65px; background-image:url(media/menu/direct.png)"></a>'
	});
	$(direct.div).find('a').click(function() {
		if (!direct.enabled) return alert(Locale7.get('error','no_login'));
		obj.gui.closeMenuLayers();
		obj.portal.openDirect('new');
	});
	
	var manage = layer.addMenu({
		id:'manage',
		w:105,
		color:'#aa0000', color2:'#890000',
		selected:{ c:'#890000', c2:'#7b0000' },
		content:'<a href="javascript://manage" style="left:-4px; width:90px; background-image:url(media/menu/manage.png)"></a>'
	});
	manage.hide();
	$(manage.div).find('a').click(function() {
		obj.portal.manage.show(manage.selected);
	});

	var my = layer.addMenu({ 
		id:'my',
		w:80,
		color:'#b5b583', color2:'#8e8e5f',
		selected: { c:'#8c8c5e', c2:'#808055' },
		enabled:false,
		content:'<a href="javascript://my" style="width:65px; background-image:url(media/menu/my.png)"></a>'
	});
	$(my.div).find('a').click(function() {
		if (!my.enabled) return alert(Locale7.get('error','no_login'));
		obj.portal.myFind(undefined,obj.layers['my'].visible);
	});
	
	var find = layer.addMenu({ 
		id:'find',
		w:80,
		color:'#b5b583', color2:'#8e8e5f',
		selected: { c:'#8c8c5e', c2:'#808055' },
		content:'<a href="javascript://find" style="width:65px; background-image:url(media/menu/find.png)"></a>'
	});
	$(find.div).find('a').click(function() { 
		obj.portal.find(undefined,obj.layers['find'].visible);
	});

	//7scenes link
	var about = layer.addMenu({ 
		id:'about',
		w:98,
		color:'#cedfe9', color2:'#8fb3ca', 
		content:'<a href="javascript://info" style="width:85px; background-image:url(media/menu/7scenes.png)"></a>'
	});
	if (this.layout!='scenes') about.hide();
	$(about.div).find('a').click(function() {
		obj.toggle(obj.portal.initialView=='home'? 'home':'page');
		about.hide();
	});

	//feedback
	var feedback = layer.addMenu({ 
		id:'feedback',
		w:90,
		color:'#050000', alpha:0,
		nodivider:true,
		content:'<a href="javascript://feedback" style="width:75px; background-image:url(media/menu/feedback.png)"></a>'
	});
	$(feedback.div).find('a').click(function() { 
		window.location = '/feedback';
	});


	/*	portal > find
	*/
	var find = this.layers.create({
		id:'find',
		w:329, y:23+4, r:0+8, h:100,
		z:250,
		bcolor:'#050000',
		gradient:'bg-black-75pct.png',
		bgrepeat:'repeat', bgtransparent:true,
		header:false,
		rounded:{ alpha:.75 },			
		hidden:true,
		parent:this.layers['portal']
	});
	$(find.content)
		.addClass('search-result')
		.before($('<div></div>')
			.attr('id','search-header')
			.addClass('search-header')
			.html(this.gui.create('search'))
		);
		
	this.gui.enableSearchInput();
	
	//portal page
	this.gui.createPortalPage();
}

Layout7.prototype.showLayers = function(layers,hide)
{
	/*	show/hide array of layers
	*/
	for (var i=0; i<layers.length; i++)
	{
		if (this.layers[layers[i]]) this.layers[layers[i]].show(hide);
	}
}

Layout7.prototype.hideLayers = function(layers)
{
	/*	hide one or multipe layers
	*/
	this.showLayers(layers,true);
}

Layout7.prototype.addLayers = function(portal)
{
	function Layers7(portal)
	{
		/*	7s Layers collection
		*/
	
		this.create = function(properties)
		{
			if (!properties.id) return;
			var layer = new Layer(portal,properties);
			//add to collection
			this[properties.id] = layer;
			
			return layer;
		}
		
		this.createMenu = function(parent,p)
		{
			/*	public link to local Menu class
			*/
			return new Menu(parent,p);
		}
		
		this.dispose = function(id)
		{
			if (!this[id]) return;
			this[id].dispose();
			delete this[id];
		}
		
		this.disposeMultiple = function(list)
		{
			var obj = this;
			$.each(list, function(i,id) {
				obj.dispose(id);
			});
		}
		
		this.disposeAll = function()
		{
			for (var id in this) if (typeof(this[id])=='object') this.dispose(id);
		}
	
		function Layer(portal,p)
		{
			/*	Layer constructor
	
				p = properties object, 
				values: id,x,y,r(ight),b(ottom),w,h,z,bcolor,hcolor,gradient,shadow,parent,hidden,align */
	
			var obj = this;
			
			this.portal = portal;
			this.parent = p.parent;
			this.id = p.id;
			
			/*	position, dimensions, style
			*/
			this.x = this.ox = p.x; //use x==undefined for right aligned fixed width layers (disables slideTo()!)
			this.y = this.oy = p.y || 0;
			this.z = p.z;
			this.align = p.align;
	
			if (p.r!=undefined)
			{
				if (this.x==undefined) this.w = p.w; //fixed width, right aligned
				this.r = p.r; //variable width
			}
			else
			{
				this.w = p.w; //fixed width
			}
			if (p.b!=undefined)
			{
				this.b = p.b; //variable height
			}
			else
			{
				this.h = p.h; //fixed height
			}
			
			this.bc = p.bcolor;			//background
			this.hc = p.hcolor;			//header
			this.hc2 = p.hcolor2;		//header gradient (bottom color)
			this.gradient = p.gradient;	//layer gradient or backdrop
			this.shadow = p.shadow; 	//dropshadow
			this.rounded = p.rounded; 	//rounded corner style (bottom-left corner only, for now)
		
			this.visible = (p.hidden)? false:true;
			this.collapsed = false;
			this.closebutton = p.closebutton;

			this.slide_speed = 0.25;
			this.resize_speed = 0.25;
			

			/*	layer container div
			*/
			var layer = $('<div></div>')
				.addClass('layer')
				.attr('id',this.id)
				.css({
					left:this.x,
					top:this.y,
					zIndex:this.z
				})
				.appendTo(this.parent.div);
			this.div = layer.get(0);


			/*	shadow, background, header
			*/
			var shadow = !p.shadow? undefined:$('<div></div>')
				.addClass('layer-shadow')
				.appendTo(layer);
			var face = $('<div></div>')
				.addClass('layer-face')
				.appendTo(layer);
			this.face = face.get(0);
			
			//shrink layer-face to reveal shadow
			if (shadow) face.css({ left:8, top:4, right:8 });
				
			$.each(['left','right'],function(i,v){
				//bg
				$('<div></div>')
					.addClass('layer-bg')
					.css({
						'left':i==0? 0:25,
						'right':i==1? 0:undefined,
						'top':(i==0 && p.header!=false)? 30:0,
						'bottom':0,
						'width':i==0? 25:undefined,
						'background':(p.bgtransparent? 'transparent':p.bcolor) + (p.gradient? ' url(media/'+p.gradient+') '+(p.bgrepeat || '')+(v=='left'? ' 0px -30px':' -25px 0px'):'')
					})
					.appendTo(face);
					
				//shadow
				if (shadow)
				{
					$('<div></div>')
						.addClass('layer-shadow-'+v)
						.appendTo(shadow);
				}
			});
				
			if (p.header!=false) this.drawHeader();

			/*	title, menu, contents
			*/
			if (p.title)
			{
				this.titlebar = $('<div></div>')
					.addClass('titlebar')
					.html(typeof(p.title)=='string'? p.title:'')
					.appendTo(face)
					.get(0);
			}

			this.addMenuBar();
			if (this.closebutton) this.addCloseButton();
			
			if (!p.nocontent)
			{
				var content = $('<div></div>')
					.addClass('layer-content')
					.appendTo(face);
				this.content = content.get(0);
			}

			this.setSize();
			
			//rounded?
			if (this.rounded) this.addRoundedCorners();
	
			//reveal
			layer.css({
				visibility:'visible',
				display:this.visible? 'block':'none'
			});
		}
		
		Layer.prototype.drawHeader = function(color)
		{
			var w = 42;
			var h = 30;
			var elm = this.header || this.face; //create canvas elm first time
			var c1 = color || this.hc
			var c2 = (!color)? this.hc2:undefined;
			
			this.header = this.portal.layout.gui.shear(elm,w,h,c1,c2);
			this.header.className = 'header';
		}
		
		Layer.prototype.addRoundedCorners = function(type)
		{
			/*	draw rounded corners with canvas, 
				->only bottom-left corner for now */

			//canvas element
			var h = this.header ? this.h-30:this.h;
			var c = document.createElement('canvas');
				c.width = 25;
				c.height = h;
				c.style.width = '25px'; //needed for safari
				c.style.height = h +'px';
		
			//remove background-color of left layer-bg and add canvas
			var bg = $(this.face)
				.find('.layer-bg:first')
				.css('background','')
				.children().remove().end()
				.append(c);
				
			//init canvas element for IE
			if (typeof(G_vmlCanvasManager)=='object') c = G_vmlCanvasManager.initElement(c);
			var ctx = c.getContext('2d');
	
			ctx.globalAlpha = (typeof(this.rounded)=='object' && this.rounded.alpha)? this.rounded.alpha:1;
	
			//bottom-left corner..		
			ctx.beginPath();
			ctx.moveTo(0,0);
			ctx.lineTo(25,0);
			ctx.lineTo(25,h);
			ctx.lineTo(10,h);
			ctx.arc(10,h-10,10,.5*Math.PI,Math.PI,false);
			ctx.lineTo(0,0);
			ctx.fillStyle = this.bc;
			ctx.fill();
			
			if (!this.bshadow)
			{
				//add dropshadow at bottom of layer
				this.bshadow = $('<div></div>')
					.addClass('layer-shadow-bottom')
					.appendTo($(this.div).css('overflow','visible'))
					.get(0);
			}
		
			//force canvas dimensions for IE
			$(c).find('div').css({
				width:25,
				height:h
			});
		}
		
		Layer.prototype.display = function(hide)
		{
			/*	temporary reveal layer in hidden state, needed for some html creation (like GMap)
			*/
			$(this.div).css('visibility',hide? 'visible':'hidden');
			this.show(hide);
		}
		
		Layer.prototype.show = function(hide)
		{
			//dbg.msg('Layer[',this.id,']: ',hide? 'hide':'show');
		
			this.visible = (hide)? false:true;
			this.div.style.display = (hide)? 'none':'block';
		}
		
		Layer.prototype.hide = function()
		{
			this.show(1);
		}
		
		Layer.prototype.update = function(p,sliding)
		{
			/*	update layer position and scale
			*/
			if (p)
			{
				this.setPosition(p.x,p.y);
				this.setSize(p.h,p.w);
			}
			else
			{
				var x,y;
				if (this.align && this.align.b) var y = this.parent.h - this.align.b;
				this.setPosition(x,y);
				this.setSize();
			}
		}
		
		Layer.prototype.setSize = function(w,h)
		{
			if (w) this.w = w;
			if (h) this.h = h;
	
			var layer = this.div;
	
			if (this.r==undefined)
			{
				layer.style.width = this.w +'px';
			}
			else 
			{
				layer.style.right = this.r +'px';
				if (this.x!=undefined) this.w = this.parent.w - (this.x+this.r);
				else layer.style.width = this.w +'px'; 
			}
			if (this.b==undefined)
			{
				layer.style.height = this.h +'px';
			}
			else
			{
				layer.style.bottom = this.b +'px';
				this.h = this.parent.h - (this.y+this.b);
			}
		
			//content
			if (this.content)
			{
				this.content.style.bottom = '0px';
				this.content.style.right = '0px';
				var pr = (this.content.style.paddingRight)? parseInt(this.content.style.paddingRight):0; //for scene layer
			}
			
			//shadow, rounded
			if (this.bshadow) this.bshadow.style.width = this.w +'px';
			if (this.rounded) this.addRoundedCorners();
		}
		
		Layer.prototype.setPosition = function(x,y)
		{
			if (x!=undefined) this.x = x;
			if (y!=undefined) this.y = y;
		
			if (this.x!=undefined) this.div.style.left = this.x +'px';
			this.div.style.top = this.y +'px';
		}
		
		Layer.prototype.slideTo = function(x,y)
		{
			if (this.x==undefined) return;
			this.tx = x;
			this.ty = y;
			
			dbg.msg('Layer[',this.id,']: slideTo(',x,',',y,')');
			
			this.slide();
		}
		
		Layer.prototype.slide = function()
		{
			var obj = this;
			
			//move to target	
			var dx = this.tx-this.x;
			var dy = this.ty-this.y;
			
			this.x = this.x + this.slide_speed*(this.tx-this.x);
			this.y = this.y + this.slide_speed*(this.ty-this.y);
			
			var update_x = (dx>0 && this.x<this.tx-1) || (dx<0 && this.x>this.tx+1);
			var update_y = (dy>0 && this.y<this.ty-1) || (dy<0 && this.y>this.ty+1);
			
			if (update_x || update_y)
			{
				this.update(undefined,true);
				//loop
				this.is_sliding = true;
				this.sliding = window.setTimeout(function() { obj.slide() },40);
			}
			else
			{
				//done, set to exact end target position
				this.is_sliding = false;
				this.x = this.tx;
				this.y = this.ty;
				this.update();
				if (this.slideCallback) this.slideCallback();
			}
		}
	
		Layer.prototype.resizeTo = function(p)
		{
			this.tw = p.tw;
			this.th = p.th;
			this.tr = p.tr;
			this.tb = p.tb;
			
			this.resize();
		}
	
		Layer.prototype.resize = function()
		{
			var obj = this;
			
			//move to target	
			if (this.tw!=undefined)
			{
				var dw = this.tw-this.w;
				this.w = this.w + this.resize_speed*(this.tw-this.w);
				var update_w = (dw>0 && this.w<this.tw-1) || (dw<0 && this.w>this.tw+1);
			}
			if (this.tr!=undefined) 
			{
				var dr = this.tr-this.r;
				this.r = this.r + this.resize_speed*(this.tr-this.r);
				var update_w = (dr>0 && this.r<this.tr-1) || (dr<0 && this.r>this.tr+1);
			}
			if (this.th!=undefined) 
			{
				var dh = this.th-this.h;
				this.h = this.h + this.resize_speed*(this.th-this.h);
				var update_h = (dh>0 && this.h<this.th-1) || (dh<0 && this.h>this.th+1);
			}
			if (this.tb!=undefined) 
			{
				var db = this.tb-this.b;
				this.b = this.b + this.resize_speed*(this.tb-this.b);
				var update_h = (db>0 && this.b<this.tb-1) || (db<0 && this.b>this.tb+1);
			}
			
	// 		this.w = this.w + this.resize_speed*(this.tw-this.w);
	// 		this.h = this.h + this.resize_speed*(this.th-this.h);
	// 		
	// 		var update_w = (dw>0 && this.w<this.tw-1) || (dw<0 && this.w>this.tw+1);
	// 		var update_h = (dh>0 && this.h<this.th-1) || (dh<0 && this.h>this.th+1);
			
			if (update_w || update_h)
			{
				this.setSize();
				//loop
				this.resizing = window.setTimeout(function() { obj.resize() },40);
			}
			else
			{
				//done, set to exact end target position
				if (this.tw) this.w = this.tw;
				if (this.tr) this.r = this.tr;
				if (this.th) this.h = this.th;
				if (this.tb) this.b = this.tb;
	
				this.setSize();
				//this.update(this.tx,this.ty);
	//			if (this.resizeCallback) this.resizeCallback();
			}
		}
		
		Layer.prototype.blur = function(elms,blur)
		{
			/*	show/hide layer features: content scrollbar, closebutton, ...
			*/
			for (var i=0; i<elms.length; i++)
			{
				switch (elms[i])
				{
					case 'content':
						$(this.content)[blur? 'hide':'show']();
						$(this.titlebar).css('overflow',blur? 'hidden':'visible');
						break;
	
					case 'backdrop':
						$(this.backdrop)[blur? 'hide':'show']();
						break;
	
					case 'scrollbar':
						$(this.content).css('overflow',blur? 'hidden':'auto');
						break;
				};
			};
		}
	
		Layer.prototype.updateBg = function(c,src)
		{
			if (!src) src = this.gradient;
			for (var i=0; i<2; i++)
			{
				var div = this.div.childNodes[i];
					div.style.backgroundColor = c || this.bc;
					div.style.backgroundImage = 'url(media/'+src+')';
			}
		}
		
		Layer.prototype.setTitle = function(html)
		{
			this.titlebar.innerHTML = html;
		}
		
		Layer.prototype.setContent = function(str)
		{
			this.content.innerHTML = str;
		}
		
		Layer.prototype.clear = function()
		{
			$(this.content).empty();
		}
		
		Layer.prototype.addContent = function(str)
		{
			this.content.innerHTML += str;
		}
		
		Layer.prototype.addCloseButton = function(src)
		{
			/*	add close button
			*/
			$(this.menubar.div).css('right',24); //move menubar to left
	
			var close = $('<div class="button"><a href="javascript://close" style="width:18px; background-image:url(media/button/close.png)"></a>')
				.css({ width:18, right:3, top:4, zIndex:5200 })
				.appendTo(this.face)
			
			//reference for event handling
			this.closebutton = close.find('a');
		}
		
		Layer.prototype.addMenuBar = function()
		{
			this.menubar = {
				parent:this,
				div:$('<div></div>')
					.addClass('menubar')
					.css('height',25) 
					.appendTo(this.face)
					.get(0)
			};
		}
	
		Layer.prototype.addMenu = function(p)
		{
			return this.menubar[p.id] = new Menu(this.menubar,p);
		}

		Layer.prototype.addMenuTo = function(elm,p)
		{
			/*	public function to create menus, 
				added to DOM element rather than this.menubar
			*/
			return new Menu({ div:elm, parent:this }, p);
		}
		
		Layer.prototype.removeMenu = function(id)
		{
			this.menubar[id].dispose();
			delete this.menubar[id];
		}
		
		Layer.prototype.showMenus = function(menus,hide)
		{
			for (var i=0; i<menus.length; i++)
			{
				if (this.menubar[menus[i]]) this.menubar[menus[i]].show(hide);
			}
		}
		
		Layer.prototype.hideMenus = function(menus)
		{
			this.showMenus(menus,true);	
		}
		
		Layer.prototype.addPanel = function(p)
		{
			/*	create and add panel
			*/
			if (!this.panels) this.panels = new Object(); //collection of panels for this pane
			
			var panel = new Panel(this,p);
			this.panels[p.id] = panel;
			
			return panel;
		}
		
		Layer.prototype.dispose = function()
		{
			//remove DOM element
			this.parent.div.removeChild(this.div)
		}
		
	
		/*	Layer Menu object
		*/
		function Menu(menubar,p)
		{
			/*	p = properties object, 
				values: id,w,color,parent,index */
			
			this.menubar = menubar;
			this.gui = this.menubar.parent.portal.layout.gui;
		
			this.id = p.id;
			this.w = p.w;
			this.h = p.h || 23;
			this.c = p.color;
			this.c2 = p.color2;
			this.alpha = p.alpha;
			this.s = p.selected || { c:'#050000', alpha:.8 }; //selected style, default: transparent black

			this.parent = menubar.div;
			this.index = p.index; //insert at specific place in bar, 0=most right
			this.enabled = (p.enabled!=undefined)? p.enabled:true; //default enabled
			
			var div = document.createElement('div');
				div.className = 'menu';
				div.style.width = this.w +'px';
				div.style.height = this.h +'px';
			
			if (this.index==undefined) this.parent.appendChild(div);
			else this.parent.insertBefore(div,this.parent.childNodes[this.index]);
			this.div = div;
	
			this.bg = this.gui.shear(div,this.w+.5,this.h,this.c,this.c2,p.alpha);
			
			//add divider (copenhagen release menu style)
			if (!p.nodivider)
			{
				$('<img>')
					.addClass('divider')
					.attr('src','media/menu/divider.png')
					.appendTo(div);
			}
		
			this.setContent(p.content || '');
			this.setEnabled(this.enabled,true);
			
			//show (will update menubar width)
			this.visible = false;
			this.show();
		}
		
		Menu.prototype.setContent = function(str)
		{
			if (!this.content)
			{
				//create content div
				var div = document.createElement('div');
					div.className = 'menucontent';
					div.style.width = this.w +'px';
					div.style.left = parseInt(this.bg.style.width) - this.w +'px';
				this.div.appendChild(div);
				this.content = div;
			}
			this.content.style.width = this.w +'px'; //might have changed
			this.content.innerHTML = str;
			
			//blur hrefs when clicked
			$(this.content).find('a').click(function() { this.blur() });
		}
		
		Menu.prototype.show = function(hide)
		{
			var show = hide? false:true;
			if (this.visible==show) return;
			
			this.visible = show;
			this.div.style.display = (this.visible)? 'block':'none';
		}
	
		Menu.prototype.hide = function(show)
		{
			this.show(true);
		}
		
		Menu.prototype.setEnabled = function(enable,force)
		{
			if (!force && this.enabled==enable) return;
			this.enabled = enable;
	
			//replace background image	
			var src = $(this.content).find('a').css('background-image');
				if (!src) return;
				src = enable? src.replace(/-disabled/,''):src.indexOf('-disabled')==-1? src.replace(/.png/,'-disabled.png'):src;
			
			$(this.content).find('a').css('background-image',src);
		}
		
		Menu.prototype.setSelected = function(select)
		{
			/*	redraw button background in select style color
			*/

			if (select==undefined) select = true;
			this.selected = select;
			
			var c = select? this.s.c:this.c;
			var c2 = select? this.s.c2:this.c2;
			var a = select? this.s.alpha:this.alpha;

			this.gui.shear(this.bg,this.w+.5,this.h,c,c2,a);
		}
	
		Menu.prototype.over = function(show)
		{
			if (this.enabled) utils.over(this.content.firstChild,show);
		}
		
		Menu.prototype.onclick = function()
		{
			//default empty, extend in object definition
		}
	
		Menu.prototype.dispose = function()
		{
			this.parent.removeChild(this.div);
		}
	

		/*	layer panel object //->REFACTOR, remove when Direct is redesigned.
		*/
		function Panel(layer,p)
		{
			/*	p = properties object,
				values: id, title, title_w, [index, h, header_w, shortcontent, content, expanded, interative] */
				
			var obj = this;
			
			this.layer = layer;
	
			this.id = p.id;
			this.title = p.title;
			this.index = p.index;
			this.content = p.content || '';
			this.shortcontent = p.shortcontent || '';
			
			this.expanded = false;
			this.interactive = (p.interactive==undefined)? true:p.interactive;
			
	//		this.can_be_collapsed = (p.collapse==undefined)? true:p.collapse;
			this.h = p.h || 100; //expanded height
			this.title_w = p.title_w; //for title graphic
			this.header_w = p.header_w || 120;
	
			//create panel
			var div = document.createElement('div');
				div.className = 'layerpanel';
				div.style.width = '98.1%';
				div.style.maxWidth = '940px';
				div.onmouseover = function() { obj.setSelected() }
				div.onmouseout = function() { obj.setSelected(false) }
			
				var panel = document.createElement('div');
					panel.className = 'content';
					
					var header = document.createElement('div');
						header.className = 'header';
						header.style.width = this.header_w +'px';
					panel.appendChild(header);
						
						var title = document.createElement('img');
							title.className = 'headertitle';
							title.style.width = this.title_w +'px';
							title.style.cursor = (this.interactive)? 'pointer':'auto';
							
// 							if (browser.cssfilter) title.onload = function() { utils.pngFix(this) }; //ie png fix
							title.src = 'media/label_panel_'+this.title+'.png';
							
							//event handling
							title.onmouseover = function() { if (obj.interactive) { utils.over(this,1); utils.over(this.parentNode.lastChild,1) } };
							title.onmouseout = function() { if (obj.interactive) { utils.over(this,0); utils.over(this.parentNode.lastChild,0) } };
							title.onclick = function() { if (obj.interactive) obj.toggleView() };
							title.onmousedown = function(e) { utils.cancelEvents(e,true) }; //prevent drag select
							
						header.appendChild(title);
							
						if (this.index!=undefined)
						{
							var headerindex = document.createElement('div');
								headerindex.className = 'headerindex';
								headerindex.innerHTML = this.index;
							header.appendChild(headerindex);
						}
						
						var expand = document.createElement('img');
							expand.style.position = 'absolute';
							expand.style.right = '6px';
							expand.style.top = '11px';
							expand.style.width = '9px';
							expand.style.height = '9px';
							expand.style.cursor = (this.interactive)? 'pointer':'auto';
// 							if (browser.cssfilter) expand.onload = function() { utils.pngFix(this) }; //ie png fix
							expand.src = 'media/icon_expand.png';
							//event handling
							expand.onmouseover = function() { if (obj.interactive) { utils.over(this,1); utils.over(this.parentNode.firstChild,1) } };
							expand.onmouseout = function() { if (obj.interactive) { utils.over(this,0); utils.over(this.parentNode.firstChild,0) } };
							expand.onclick = function() { if (obj.interactive) obj.toggleView() }
							expand.onmousedown = function(e) { utils.cancelEvents(e,true) }; //prevent drag select
							
						header.appendChild(expand);
					
					var content = document.createElement('div');
						content.style.marginLeft = this.header_w+15 +'px';
						content.style.marginTop = '8px';
					panel.appendChild(content);
	
						var collapsed = document.createElement('div');
							collapsed.innerHTML = this.shortcontent;
						content.appendChild(collapsed);
	
						var expanded = document.createElement('div');
							expanded.style.display = 'none';
							expanded.innerHTML = this.content;
						content.appendChild(expanded);
	
			div.appendChild(panel);
			this.div = div;
	
			this.panel = panel;
			this.header = header;
	
			this.shortcontent = collapsed;
			this.content = expanded;
			
			if (layer.content.firstChild && layer.content.firstChild.tagName.toLowerCase()=='form')
			{
				//form present (directmode)
				layer.content.firstChild.appendChild(div);
			}
			else
			{
				layer.content.appendChild(div);
			}
	
			//create and draw canvas arrow
			if (this.index>1) this.addArrow();
	
			//expanded by default
			if (p.expanded || p.expanded==undefined) this.expand(1); 
		}
		
		Panel.prototype.addArrow = function(style)
		{
			var canvas = document.createElement('canvas');
				canvas.className = 'arrow';
				canvas.width = 40;
				canvas.height = 20;
				if (style=='bottom')
				{
					canvas.style.right = '80px';
					canvas.style.bottom = '-20px';
				}
				else //default top
				{
					canvas.style.top = '-12px';
					canvas.style.bottom = '-20px';
				}
			this.div.appendChild(canvas);
	
			//init canvas element for IE
			if (typeof(G_vmlCanvasManager)=='object') canvas = G_vmlCanvasManager.initElement(canvas);
				
			var ctx = canvas.getContext('2d');
		
			ctx.beginPath();
			ctx.moveTo(0,0);
			ctx.lineTo(40,0);
			ctx.lineTo(20,20);
			ctx.lineTo(0,0);
			ctx.fillStyle = '#999966';
			ctx.fill();
			//shadow
			ctx.beginPath();
			ctx.moveTo(0,0);
			ctx.lineTo(20,20);
			ctx.strokeStyle = '#75744a';
			ctx.stroke();
			//highlight
			ctx.beginPath();
			ctx.moveTo(40,0);
			ctx.lineTo(20,20);
			ctx.strokeStyle = '#baba86';
			ctx.stroke();
		}
		
		Panel.prototype.setSelected = function(select,force)
		{
			if (!this.interactive && !force) return;
		
			var select = (select || select==undefined)? true:false;
			if (this.selected==select) return;
			
			this.selected = select;
			
			this.panel.style.backgroundImage = (select)? 'url(media/bg-direct-panel-gradient.png)':'';
			this.panel.style.backgroundColor = (select)? '#b2b277':'transparent';
			this.header.style.backgroundImage = (select)? 'url(media/bg-direct-panel-gradient-header.png)':'';
			this.header.style.backgroundColor = (select)? '#949461':'#878758';
		}
		
		Panel.prototype.toggleInteractive = function()
		{
			this.interactive = !this.interactive;
	
			//(re)set cursor for header title and arrow
			this.header.firstChild.style.cursor = (this.interactive)? 'pointer':'auto';
			this.header.lastChild.style.cursor = (this.interactive)? 'pointer':'auto';
		}
	
		Panel.prototype.toggleView = function()
		{
			if (this.expanded) this.collapse();
			else this.expand();
		}
		
		Panel.prototype.expand = function(force,collapse)
		{
			if (!this.interactive && !force) return;
	
			this.expanded = (collapse)? false:true;
	
			this.setHeight();
			this.header.lastChild.src = (this.expanded)? 'media/icon_expanded.png':'media/icon_expand.png';
	
			//toggle expanded and collapsed content
			this.shortcontent.style.display = (this.expanded)? 'none':'block';
			this.content.style.display = (this.expanded)? 'block':'none';
	
			this.setSelected(this.expanded,force);
	
			//additional actions (defined in object)		
			this.onexpand();
		}
		
		Panel.prototype.collapse = function(force)
		{
			this.expand(force,true);
		}
		
		Panel.prototype.onexpand = function()
		{
			//default empty, extend in object
		}
		
		Panel.prototype.setHeight = function(h)
		{
			if (h!=undefined) this.h = h; //update
			this.panel.style.height = (this.expanded)? this.h+'px':'35px';
			this.header.style.height = (this.expanded)? this.h+'px':'35px';
			this.content.style.height = (this.expanded)? (this.h-8)+'px':'35px';
		}
		
		Panel.prototype.setShortContent = function(str)
		{
			this.shortcontent.innerHTML = str;	
		}
		
		Panel.prototype.setContent = function(str)
		{
			this.content.innerHTML = str;	
		}
		
		Panel.prototype.addContent = function(str)
		{
			this.content.innerHTML+= str;
		}
		
		Panel.prototype.addMenu = function(p)
		{
			if (!this.menubar) 
			{
				//add menubar first
				this.menubar = {
					parent:this.layer,
					div:$('<div/>')
						.addClass('menubar')
						.css('height',20)
						.appendTo(this.div)
						.get(0)
				};
			}
	
			//add menu
			var menu = new Menu(this.menubar,p);
			this.menubar[p.id] = menu;
			
			return menu;
		}
	
		Panel.prototype.addButton = function(type,position)
		{
			var imgtype = 'icon';
			var button = document.createElement('img');
				button.style.position = 'absolute';
				button.style.cursor = 'pointer';
		
			if (position)
			{
				for (var p in position)
				{
					button.style[p] = position[p] +'px';
				}
			}
			else
			{
				//default positions
				switch (type)
				{
					case 'save':
					case 'next':
					case 'done':
						imgtype = 'button';
						button.style.right = '80px';
						button.style.bottom = '1px';
						button.style.width = '43px';
						button.style.height = '18px';
						break;
						
					case 'help':
						button.style.right = '17px';
						button.style.top = '7px';
						button.style.width = '18px';
						button.style.height = '18px';
						break;
						
					case 'close':
						button.style.right = '125px';
						button.style.bottom = '1px';
						button.style.width = '18px';
						button.style.height = '18px';
						break;
				}
			}
	
			//ie png fix
// 			if (browser.cssfilter) button.onload = function() { utils.pngFix(this) };
			button.src = 'media/'+imgtype+'_'+type+'.png';
			//event handling
			button.onmouseover = function() { utils.over(this,1) }
			button.onmouseout = function() { utils.over(this,0) }
			
			this.div.appendChild(button);
			this[type+'button'] = button;
			return button;
		}
		
		Panel.prototype.removeButton = function(type)
		{
			if (!this[type+'button']) return;
			this.div.removeChild(this[type+'button'])
			delete this[type+'button'];
		}
	}
	
	/*	add layers collection
	*/
	this.layers = new Layers7(portal);
}

/* [file src="base/Layout.Gui.js"]
*/
/*	usemedia.com . joes koppers . 07.2008, rev 01.2010
	thnx for reading this code */


/*	7s base Gui
*/

Layout7.prototype.addGui = function()
{
	function Gui(layout)
	{
		//references
		this.layout = layout;
		this.portal = layout.portal;
		
		//defaults
		this.inputIgnoredKeys = { 9:'tab',16:'shift',17:'ctrl',18:'alt',224:'apple',37:'arrow',38:'arrow',39:'arrow',40:'arrow' };
	}

	
	/*	Portal page
	*/
	Gui.prototype.createPortalPage = function()
	{
		/*	portal layer ("scenes") panels 
		*/
		var obj = this;
		var layer = this.layout.layers['portal'];
			layer.panels = new Object();

		var coverflow = this.createPanel('coverflow',920)
			.css({
				'margin-top':18
			})
			.appendTo(layer.content)
			.find('.panel-body')
			.css('height',196)
			.end();
		
			//add menubar (to content, not header due to canvas z-index)
			var menubar = $('<div/>')
				.addClass('menubar')
				.css({
					height:25,
					right:1,
					top:-35
				})
				.appendTo('#layer-panel-coverflow .panel-body');

			//coverflow menus
			$.each(['popular','featured'], function(i,v) {
				var menu = layer.addMenuTo(menubar.get(0), {
					id:v,
					w:110,
					color:'#050000', alpha:.2,
					selected:{ c:'#050000', alpha:0 },
					content:'<a href="javascript://'+v+'" style="width:85px; background-image:url(media/menu/'+v+'.png)"></a>'
				} );
				
				$(menu.div).find('a').click(function() {
					obj.portal.getCoverScenes(v);
				});
				
				//store menu reference in panel data
				coverflow.data(v,menu);	
			});
		
		//add panel ref
		layer.panels['coverflow'] = coverflow;
		
		/*	create coverflow
		*/
		this.coverflow = new Canvasflow(this.portal,coverflow);
	}

	function Canvasflow(portal,panel)
	{
		this.portal = portal;
		this.gui = portal.gui;

		var w = 916, h = 231;
		
		//settings, 9 positions, 4 is center, 0 and 8 are hidden
		this.position = 4;
		this.positions = [
			{ index:0,	x:15,	y:17,	s:0.5, 	o:0 },
			{ index:1,	x:56,	y:37, 	s:0.75,	o:1 },
			{ index:2,	x:117,	y:62,	s:1,   	o:1 },
			{ index:3,	x:195,	y:86,	s:1.3,	o:1 },
			{ index:4,	x:303,	y:97,	s:2.25,	o:0 },
			{ index:5,	x:534,	y:86, 	s:1.3,	o:1 },
			{ index:6,	x:666,	y:69,	s:1,   	o:1 },
			{ index:7,	x:782,	y:49,	s:0.75,	o:1 },
			{ index:8,	x:874,	y:23,	s:0.5, 	o:0 }
		];
		this.snap = 1.5;
		
		//container + canvas
 		var content = panel
 			.mousedown(function(e) {
 				e.preventDefault();
 			})
			.find('.content');
 			
		var c = document.createElement('canvas');
			c.id = 'coverflow';
			c.width = w;
			c.height = h;
			c.style.width = w +'px';
			c.style.height = h +'px';

		content.append(c);
		
		//init canvas element for IE
		if (typeof(G_vmlCanvasManager)=='object') c = G_vmlCanvasManager.initElement(c);

		this.canvas = c;
		this.ctx = c.getContext('2d');

		//canvas event handling
		var obj = this;
		$(c)
			.find('div').css({ //force canvas dimensions for IE
				width:w,
				height:h
			}).end()
			.click(function(e) {

				var x = e.clientX - $(e.currentTarget).offset().left;
				var target;
				for (var i=1; i<obj.positions.length-1; i++)
				{
					if (x>obj.positions[i].x) target = i;
				}
	
				//find item at target position
				var position;
				$.each(obj.items, function(i,item) {
					if (item.current==target)
					{
						position = item.index;
						return false;
					}
				});
				if (position!=undefined && obj.position!=position) obj.browse(position);
			})
			.mousedown(function(e) {
				e.preventDefault();
			});

		//slider control
		this.slider = $('<div/>')
			.attr('id','cover-slider')
			.html('<div class="container"><img id="cover-slider-handle" src="media/slider_handle.png"></div>')
			.appendTo(content)
			.find('img')
			.draggable({
				addClasses:false,
				axis:'x',
				containment: 'parent',
				start:function() {
					$(this).attr('src','media/slider_handleX.png');
				},
				drag:function(event,ui) {
					var p = Math.floor(ui.position.left * (obj.items.length/215)) - (Math.floor(obj.items.length/2) - 4);
					if (p!=obj.position) obj.browse(p,true);
				},
				stop:function(event,ui) {
					$(this).attr('src','media/slider_handle.png');
				}
			});

		//selected scene
		this.selected = $('<div/>')
			.attr('id','cover-selected')
			.appendTo(content)
			.click(function() {

				/*	open scene
				*/
				obj.portal.foundScene(obj.scene);

			});
	}
	
	Canvasflow.prototype.clear = function(all)
	{
		this.ctx.clearRect(0,0,$(this.canvas).width(),$(this.canvas).height());
		if (all)
		{
			this.selected.hide();
			$('#cover-slider').hide();
		}
	}
	
	Canvasflow.prototype.update = function(records)
	{
		/*	create and add elements to coverflow
		*/
		this.items = new Array();
		$('#cover-slider').hide();
		
		var obj = this;
		$.each(records, function(i,rec) {
		
			//initial position (middle item in list is centered)
			var n = i - (Math.floor(records.length/2) - 4);
			var c = Math.min(8,Math.max(0,n));
			var p = obj.positions[c];
			if (n==4) obj.scene = rec;
			
			var item = {
				content:rec,
				index:n,
				current:c,
				position:{
					x:p.x, y:p.y, s:p.s, o:p.o
				},
				draw:{
					x:p.x, y:p.y, s:p.s, o:p.o
				},
				slide:function(tp) {
				
					if (this.sliding) window.clearTimeout(this.sliding);
					var p = this.position;

					var update;
					$.each(p, function(key,value) {
						var d = tp[key] - value;
						value += .28 * (d);
						p[key] = value;
						if ((d>0 && value<tp[key]-obj.snap) || (d<0 && value>tp[key]+obj.snap)) update = true;
					});

					if (update)
					{
						//sliding
						this.redraw = true;
						var item = this;
						this.sliding = window.setTimeout(function() { item.slide(tp) },15);
					}
					else
					{
						//done, update data.position to exact target
						if (tp.index==4) obj.scene = rec;
						this.current = tp.index;
						this.redraw = false;
						p.x = tp.x;
						p.y = tp.y;
						p.s = tp.s;
						p.o = tp.o;
					}
					
					//update draw state
					this.draw= {
						x:p.x,
						y:p.y,
						s:p.s,
						o:p.o
					}
				}
			}

			//add scene-icon
 			if (rec.getField && rec.getField('sceneiconid'))
 			{
				item.icon = new Image();
				item.icon.onload = function() { $(this).data('loaded',true) };
				item.icon.src = obj.gui.sceneIconUrl('large',rec);
			}
					
			obj.items.push(item);		
		});

		//get images
		this.preload();
	}
	
	Canvasflow.prototype.preload = function()
	{
		/*	wait for all scene icons to be loaded, draw when done
		*/
		var obj = this;
		
		if (!this.shadow)
		{
			//add drop shadow first
			this.shadow = new Image();
			this.shadow.onload = function() { $(this).data('loaded',true) };
			this.shadow.src = 'media/bg-cover-shadow.png';
		}
		else if (!$(this.shadow).data('loaded'))
		{
			//wait for dropshadow to be loaded
			return window.setTimeout(function() { obj.preload() },100);
		}
		
		var wait;
		$.each(this.items, function(i,item) {
			if (item.icon && !$(item.icon).data('loaded')) wait = true;
		});
		
		if (wait)
		{
			window.setTimeout(function() { obj.preload() },50);
		}
		else
		{
			$(this.slider).css('left',(Math.floor(this.items.length/2) * (215/this.items.length)));
			$('#cover-slider').show();
			this.draw();
		}
	}
	
	Canvasflow.prototype.draw = function(callback)
	{
		/*	draw all items on canvas
		*/
		if (this.drawing) window.clearTimeout(this.drawing);
		
		this.clear();
		
		var obj = this;
		var redraw = false;
		$.each(this.items, function(i,item) {

			var p = item.draw;

			//drop shadow
			if (p.o==1 || $.support.opacity)
			{
				obj.ctx.globalAlpha = item.draw.o;
				obj.ctx.drawImage(obj.shadow,p.x+2,p.y+3,110*p.s,53*p.s);
				$(obj.canvas).find('div').find('image:last').css({ left:0, top:0 }); //fixes display bug on IE7
			}
			//draw shear
			obj.gui.shear(
				obj.canvas,
				65*p.s,
				47*p.s,
				'#dddfb2',
				{ type:'stroke', color:'#dddfb2', width:2*p.s, fill:'#999966' },
				p.o,
				{ x:p.x, y:p.y }
			);
			//scene-icon
			if (item.icon && (p.o==1 || $.support.opacity))
			{
				obj.ctx.drawImage(item.icon,
					Math.floor(p.x+(4*p.s)),
					p.y+(2*p.s),
					Math.round(97*p.s),
					Math.round(43*p.s)
				);
				$(obj.canvas).find('div').find('image:last').css({ left:0, top:0 }); //fixes display bug on IE7
			}
			//gloss
			var d = Math.tan((Math.PI/180)*40) * (47*p.s);
			obj.gui.shear(
				obj.canvas,
				65*p.s,
				47*p.s,
				'#dddfb2',
				{ type:'gradient', x:p.x+d+1 , y:p.y, x2:p.x+(63*p.s), y2:p.y+(47*p.s), stops:[
					{ p:0, c:'rgba(239,241,192,0.75)' },
					{ p:.35, c:'rgba(239,241,192,0.5)' },
					{ p:.55, c:'rgba(239,241,192,0)' }
				] },
				p.o,
				{ x:p.x, y:p.y }
			);

			if (item.redraw) redraw = true;
		});
		
		if (redraw)
		{
			/*	redraw canvas until all items are done
			*/
			this.drawing = window.setTimeout(function() { obj.draw() },35);
		}
		else
		{
			if (callback) callback();
			else this.draw(function() { obj.select() });
		}
	}
	
	Canvasflow.prototype.select = function()
	{
		/*	update and show selected scene
		*/
		this.selected
			.html(this.gui.create({ id:'scene_cover_info', rec:this.scene }))
			.show();
	}
	
	Canvasflow.prototype.browse = function(index,slider)
	{
		/*	put item with index at center position (4)
		*/
		this.position = index;

		//hide info
		this.selected.hide();
		//update slider
		if (!slider) $(this.slider).css('left',(index + (Math.floor(this.items.length/2) - 4)) * (215/this.items.length));
		
		var d = 4-index;
		var obj = this;
		$.each(this.items, function(i,item) {
			item.slide(obj.positions[Math.min(8,Math.max(0,item.index+d))]);
		});
		
		//start redrawing
		this.draw();
	}


	/*	Layer features
	*/
	Gui.prototype.enableLoginMenu = function()
	{
		/*	create login menu gui:
			input form, logged in/out status */
	
		var login = this.layout.layers['portal'].menubar['login'];
		var obj = this.portal;
		
		$(login.div).click(function(){
 			if (login.expanded) return;
 			if (!obj.login.id) login.expand(1);
 			
 			obj.layout.resize();

			//reset search layer
			obj.find(0,true);
		});

		login.expand = function(expand)
		{
			this.content.style.visibility = 'hidden'; //hide while update
			this.expanded = expand;
			this.prevw = this.w;
			this.w = (this.expanded)? 500:90;
			this.div.style.width = this.w +'px';
			//redraw bg
			obj.gui.shear(this.bg,this.w,23,this.c,this.c2);
			
			if (!this.expanded)
			{
				/*	login or logout menu
				*/
				if (!obj.login.id) 
				{
					//login
					this.setContent('<a href="javascript://login" style="width:65px; background-image:url(media/menu/login.png)"></a>');
				}
				else
				{
					//profile and logout
					this.setContent( obj.gui.create('logout') );

					$(this.content).find('div, a:first')
						.attr('title',Locale7.get('gui','profile').replace('$1',obj.login.loginname))
						.click(function(e) {
							obj.login.profile.show(login.selected);
							e.stopPropagation();
						})
						.filter('div')
						.hover(function() {
							$(this).next().addClass('button-over');
						}, function() {
							$(this).next().removeClass('button-over');
						});
					
					$(this.content).find('a:last')
						.attr('title',Locale7.get('gui','logout'))
						.click(function(e) {
							obj.logout();
							e.stopPropagation();
						});
				}
			}
			else
			{
				/*	login form
				*/
				this.setContent( obj.gui.create('loginform') );
				
				//cancel and login buttons
				var loginobj = this;
				
				$('<div class="button"><a href="javascript://cancel" style="width:18px; background-image:url(media/button/close.png)"></a>')
					.css({ width:18, right:69, top:3 })
					.appendTo($(this.content))
					.click(function(e) {
						loginobj.expand(0);
						e.stopPropagation();
					});
					
				$('<div class="button"><a href="javascript://login" style="width:43px; background-image:url(media/button/login.png)"></a>')
					.css({ width:43, right:25, top:3 })
					.appendTo($(this.content))
					.click(function() {
						obj.doLogin();
					});
					
				
				//lost password
				$('#lostpassword').click(function() {
					obj.lostPassword();
				});
				
				//form focus and enter-key handling
				var form = document.forms['loginform'];
				window.setTimeout(function() { form.login.focus() },100);

				var submit = function(e)
				{
					if (!e) e = event;
					if (e.keyCode==13) return obj.doLogin();
				}
				form.password.onkeydown = submit;
				form.login.onkeydown = submit;
				
				//auto-login toggle
				form.autologin.checked = obj.login.set_autologin;
				utils.over(form.autologin.nextSibling,obj.login.set_autologin);
				form.autologin.onchange = function() { obj.setAutoLogin('toggle') }
			}
			
			//reveal content
			this.content.style.visibility = 'visible';
		}
	}
	
	Gui.prototype.enableSearchInput = function(my)
	{
		/*	add keyboard input handling for (my)Find menu
		*/
		var form = document.forms[(my? 'my':'')+'searchform'];
	
		//input
		var obj = this.portal;
		var ignoreKeys = this.inputIgnoredKeys;
		form.query.onkeydown = function(e)
		{
			/*	execute search at small delay if input is more than 1 chars
			*/
			if (!e) e = event;
			if (obj.searching) window.clearTimeout(obj.searching);
			if (ignoreKeys[e.keyCode]) return e.returnValue;
			else
			{
				obj.searching = window.setTimeout(function() { obj.query(undefined,form.query.value,my) },500);
				return e.returnValue;
			}
		}
		
		//clear input
		$('#'+(my? 'my-':'')+'search-header .button:first').find('a')
			.click(function() {
				obj.query(undefined,'',my);
				$(form.query).val('').focus();
			});

		//context (only used for myFind at the moment: directed, played and invited scenes)
		if (my)
		{
			$('#my-search-context')
				.css('display','block')
				.find(':radio')
				.click(function() {
					$('#my-search-context').find(':radio').next().attr('src','media/checkbox.png');
					//refresh display
					obj.query(undefined,form.query.value,true);
				});
		}
		else
		{
			$('#search-context-toggle').css('display','none');

			//->search within project context, could be re-added later
// 			if (this.project)
// 			{
// 				var name = this.project.name;
// 				if (name.length>15) name = name.substring(0,15)+'..';
// 				document.getElementById('search-context').innerHTML = name;
// 			}
		}
	}
	
	Gui.prototype.alignMenuLayer = function(menu)
	{
		/*	align portal menu-layers to find menu
		*/
		var layers = this.layout.layers;
		var m = layers['portal'].menubar['find'];
		var w = $(m.parent).width() - $(m.div).position().left;
		layers[menu].setSize(w-1);
	}
	
	Gui.prototype.closeMenuLayers = function(exclude)
	{
		/*	close all portal menu layers
		*/
		var p = this.portal;
		var m = this.layer.menubar;
		if (exclude!='find' && m.find.selected) p.find(undefined,true);
		if (exclude!='myfind' && m.my.selected) p.myFind(undefined,true);
		if (exclude!='profile' && m.login.selected) p.login.profile.show(true);
		if (exclude!='manage' && m.manage.selected) p.manage.show(true);
	}
	
	Gui.prototype.updateSearchResult = function(list,offset,my,channel)
	{
		/*	create and display search result list, 
			with offset navigation if length>max */
			
		offset = offset || 0;
		var m = my? 'my':'';
		var max = this.portal.view=='home'? 10:20;
		var layer = channel || this.layout.layers[my? 'my':'find'];
		
		//reset layer
		$(layer.content).empty();
		if (!channel) layer.setSize(undefined,100);

		//update header (and layer if return true)
		if (this.updateSearchHeader(layer,list,offset))
		{
			//height of layer
			if (!channel)
			{
				var h = (list.length<max || list.length-offset<max)? Math.min(list.length,list.length-offset)*20:max*20;
				layer.setSize(undefined,100+h);
			}
			
			//create and add list elements
			var obj = this;
			var by = Locale7.get('gui','by');
			var off = my? 50:150;
			var maxl = Math.round((layer.w-off)/7); //max chars for scene name
			
			for (var i=offset; i<Math.min(offset+max,list.length); i++)
			{
				var name = list[i].getField('name');
				if (name.length>maxl) name = name.substring(0,maxl)+'..';
				
				var user = list[i].getField('user');
				if (user.length>16) user = user.substring(0,16)+'..';
			
				var str = '<img src="media/icon_scene_list_'+list[i].getField('state')+'.png">';
					str+= name;
					if (!my) str+= ', '+by+' <b>'+user+'</b>';
	
				$('<div></div>')
					.addClass('search-result-listelement')
					.attr('title','"'+list[i].getField('name')+'" '+by+' '+list[i].getField('user'))
					//.data('index',i)
					.data('rec',list[i])
					.css('margin-top',i==offset && !channel? 8:0)
					.html(str)
					.hover(function(){
						$(this).css('background-color','#4089a9');
					}, function() {
						$(this).css('background-color','transparent');
					})
					.click(function() {
						if (!channel)
						{
							//close search
							obj.portal[my? 'myFind':'find'](undefined,true);
						}
						else
						{
							//close channel
							obj.portal.scene.openMenu('channel',true);
						}
						
						/*	open scene
						*/
						obj.portal.foundScene($(this).data('rec'),my);
					})
					.appendTo(layer.content);
			}
		}
	}

	Gui.prototype.updateSearchHeader = function(layer,list,offset)
	{
		/*	update search result header, 
			generic, used for (my)find and menu-layer widgets */
			
		var header = $(layer.div).find('.result-header').children().empty().end();
		var type = (layer.id=='my' || layer.id=='find' || layer.id=='channel')? 'find':layer.id;
		var max = type=='find' && this.portal.view!='home'? 20:10;
		var my = layer.id.indexOf('my')!=-1;

		if (typeof(list)=='string')
		{
			switch(list)
			{
				case 'searching':
					var s = '';
					//if (my) s = '-my';
					if (layer.id=='traces' || layer.id=='events' || layer.id=='channel') s = '-widget';
					
					header.find('.result-nav')
						.html('<img src="media/loading'+s+'-search.gif" style="position:absolute; right:0px; top:-1px">');
					break;
					
				case 'reset':
					header.find('input').val('');
					break;
			}		
			
			//reset layer height
			return false;
		}

		if (list.length==0)
		{
			var str = Locale7.get('gui','find_zero').replace('$1',type=='find'? 'scenes':type);
		}
		else
		{
			var str = (list.length>100)? '100+ ':list.length+' ';
				str+= type=='find'? 'scene':type.substr(0,type.length-1);
				if (list.length>1) str+= 's';
				str+= ' '+Locale7.get('gui','find_result');
		}
		header.find('.result-count').html(str);
		
		//paging
		var nav = header.find('.result-nav');
		if (list.length>max)
		{
			nav.html((offset+1)+'...'+Math.min(offset+max,list.length));
			
			//prev
			if (offset>0)
			{
				addButton(this,'left',offset-max,my);
			}
			//next
			if (offset<list.length-max && offset<100-max)
			{
				addButton(this,'right',offset+max,my);
			}
		}
		
		var obj = this;
		function addButton(gui,style,offset)
		{
			$(gui.create({ id:'button', title:style=='left'? 'prev':'next', src:'browse_'+style }))
				.css({ width:14, top:0 })
				.css(style,0)
				.appendTo(nav)
				.find('a').click(function() {
					if (type=='find')
					{
						obj.updateSearchResult(list,offset,my,layer.id=='channel'? layer:undefined);
					}
					else
					{
						obj.updateWidgetList(type,list,offset);
					}
					this.blur();
				});
		};
		
		return true;
	}

	Gui.prototype.sceneIconUrl = function(size,icon)
	{
		/*	return icon url for a scene icon object
		*/
		if (icon.getField)
		{
			//get values from record
			var icon = {
				id:icon.getField('sceneiconid'),
				scale:icon.getField('scale'),
				offsetx:icon.getField('offsetx'),
				offsety:icon.getField('offsety')
			}
		}
		var x = Number(icon.offsetx); 
		var y = Number(icon.offsety);
		var s = Number(icon.scale);
		var crop = (x>0? '-'+x:'+'+Math.abs(x))+(y>0? '-'+y:'+'+Math.abs(y));
		
		var d;
		switch(size)
		{	
			case 'small': d = '63x28'; s = s * (63/97); break;
			case 'medium': d = '97x43'; break;
			case 'large': d = '126x56'; s = s * (126/97); break;
		}

		return this.portal.path+'media.srv?id='+icon.id+'&cmd=sceneicon-'+size+'&crop='+d+encodeURIComponent(crop)+'&geometry='+encodeURI(s*100+'%')+'&format=png';
	}

	
	/*	general gui elements
	*/	
	Gui.prototype.createPanel = function(id,w)
	{
		/*	portal page panels
				id	string: panel id
				w	number/string: width in pixels */

		var bg = '<div class="bg left"></div><div class="bg right"></div>';
		return $('<div class="layer-panel"></div>')
			.attr('id','layer-panel-'+id)
			.css('width',w)
			.html(
				'<div class="panel-header">'+bg+'</div>'+
				'<div class="panel-body">'+bg+'<div class="content"></div></div>'+
				'<div class="panel-footer">'+bg+'</div>'
			);	
	}

	Gui.prototype.button = function(title,img,w,txt)
	{
		/*	create standard href button html with optional txt
		*/
		return $('<div></div>')
			.addClass('button')
			.html('<a href="javascript://'+title+'" style="width:'+(w||18)+'px; background-image:url(media/button/'+(img||title)+'.png)">'+(txt? txt:'')+'</a>');
	}
	
	Gui.prototype.embedMedium = function(parent,medium,w,h,options,bgcolor)
	{
		/*	use jw_flvplayer/swfobject to embed a medium
				parent		html elment container for player
				medium		medialib object (width medium.id, medium.type)
				[w,h]		dimensions of embeded medium
				[options]	optional override flashvars (e.g. controlbar=none)
				[bgcolor]	optional background color */
		
		var id = medium.id;
		var w = w || 200;
		var h = h || 150;
		var format = (medium.type=='video')? 'flv':'mp3';
		var bg = bgcolor || '#0D3040';
		
		var thumb = (medium.type=='video')? this.portal.path+'media.srv?id='+id+'%26format=jpg%26resize=x'+h+'%26.jpg':'';
		var src = this.portal.path+'media.srv?id='+id+'%26format=flv%26resize=x'+h+'%26.'+format; //we add an extension, otherwise flvplayer won't play
		var display = document.getElementById('place_medium');

		//player container div
		var div = document.createElement('div');
		div.id = 'medium_embed_'+new Date().getTime();
		parent.appendChild(div);

		//init swf player
		var playerid = 'player'+new Date().getTime();
		var flashvars = (medium.type=='video')? 'fullscreen=true':'';
			flashvars += options || '';
		
		var s1 = new SWFObject('media/player.swf',playerid,w,h,'9',bg);
		s1.addParam('allowfullscreen','true');
		s1.addParam('allowscriptaccess','always');
		s1.addParam('wmode','opaque');
		s1.addParam('flashvars','file='+src+'&image='+thumb+'&skin=media/nacht.swf&'+flashvars);
		s1.write(div.id);
		
		return playerid;
	}
	
	Gui.prototype.shear = function(elm,w,h,color,style,alpha,add)
	{
		/*	(create and) draw sheared canvas graphic, params:
				elm			parent to append shear, or canvas element (for color update or draw over)
				w,h			(non sheared) dimensions
				color		base color of shear
				[style]		optional color value for gradient (bottom color) or object for stroked shear (style.color, [style.width], [style.fill])
				[alpha]		optional opacity (0-1)
				[add]		draw onto existing canvas with offsets (add.x, add.y) */

		//dimensions
		var a = (Math.PI/180) * 40; //shear angle
		var s = h * Math.tan(a);
		var width = Math.round(w+s);
		
		//get canvas context (create if needed)
		if (elm.nodeName.toLowerCase()!='canvas')
		{
			var canvas = document.createElement('canvas');
				canvas.width = width;
				canvas.height = h;
				canvas.style.width = width +'px'; //needed for safari
				canvas.style.height = h +'px';
			elm.appendChild(canvas);
			//init canvas element for IE
			if (typeof(G_vmlCanvasManager)=='object') canvas = G_vmlCanvasManager.initElement(canvas);
			var ctx = canvas.getContext('2d');
		}
		else
		{
			var canvas = elm;
			var ctx = elm.getContext('2d');
			if (!add)
			{
				//resize if needed
				if (elm.width!=Math.round(w+s)) { elm.width = Math.round(w+s); elm.style.width = Math.round(w+s) +'px' };
				if (elm.width!=h) { elm.height = h; elm.style.height = h +'px' };
			}
		}
		
		//clear current canvas
		if (!add)
		{
			var a = { x:0, y:0 };
			ctx.clearRect(0,0,w+s,h);
		}
		else
		{
			a = add;
		}

		ctx.globalAlpha = alpha!=undefined? alpha:1;
		
		ctx.beginPath();
		ctx.moveTo(a.x+s,a.y+0);
		ctx.lineTo(a.x+w+s,a.y+0);
		ctx.lineTo(a.x+w,a.y+h);
		ctx.lineTo(a.x+0,a.y+h);

		if (style) 
		{
			if (typeof(style)=='object')
			{
				switch (style.type)
				{
					case 'stroke':
					
						/*	stroked (and filled) shear 
						*/
						if (style.fill)
						{
							ctx.fillStyle = style.fill;
							ctx.fill();
						}
						ctx.lineWidth = style.width || 1;
						ctx.strokeStyle = style.color;
		
						var offset = ctx.lineWidth/2; //offset for sharp pixellines
						ctx.beginPath();
		
						ctx.moveTo(a.x+s,a.y+0+offset);
						ctx.lineTo(a.x+w+s-offset,a.y+0+offset);
						ctx.lineTo(a.x+w,a.y+h-offset);
						ctx.lineTo(a.x+0+offset,a.y+h-offset);
						ctx.lineTo(a.x+s,a.y+0+offset);
						
						ctx.stroke();
						break;
					
					case 'gradient':
					
						/*	angled linear gradient with multiple colorstops
						*/
						var gradient = ctx.createLinearGradient(style.x,style.y,style.x2,style.y2);
						$.each(style.stops, function(i,stop) {
							gradient.addColorStop(stop.p,stop.c);
						});
						
						ctx.fillStyle = gradient;
						ctx.fill();
						break;
				}
			}
			else
			{
				//use gradient
				var gradient = ctx.createLinearGradient(0,0,0,h);
					ctx.globalAlpha = alpha || 1;
					gradient.addColorStop(0, color);
					ctx.globalAlpha = alpha || 1;
					gradient.addColorStop(1, style);
				ctx.fillStyle = gradient;
				ctx.fill();
			}
		}
		else 
		{
			ctx.fillStyle = color;
			ctx.fill();
		}
		
		//force canvas dimensions for IE
		if (!add)
		{
			$(canvas).find('div').css({
				width:width,
				height:h
			});
		}
		
		return canvas;
	}

	Gui.prototype.draw = function(elm,p)
	{
		/*	create canvas with drawn shape of p.type, append to elm
		*/
		var c = document.createElement('canvas');
			c.width = p.w;
			c.height = p.h;
			c.style.width = p.w +'px';
			c.style.height = p.h +'px';

		elm.append(c);
		
		//init canvas element for IE
		if (typeof(G_vmlCanvasManager)=='object') c = G_vmlCanvasManager.initElement(c);

		var ctx = c.getContext('2d');
		
		//draw
		switch (p.type)
		{
			case 'circle':
				var x = (p.w/2);
				var y = (p.h/2);
				var r = p.r;
				ctx.beginPath();
				ctx.globalAlpha = p.alpha || 1;
				ctx.arc(x,y,r,0,2*Math.PI,true);
				ctx.fillStyle = p.c;
				ctx.fill();
				
				if (p.stroke)
				{
					ctx.strokeStyle = p.stroke.c;
					ctx.lineWidth = p.stroke.w || 1;
					ctx.globalAlpha = p.stroke.alpha || p.alpha || 1;
					ctx.stroke();
				}
				break;
		}

		//force canvas dimensions for IE
		$(c).find('div').css({
			width:p.w,
			height:p.h
		});
		
		return c;
	}


	/* HTML
	*/
	Gui.prototype.create = function(p)
	{
		/*	build and return (HTML) string,
			p = properties object (with p.id) or an id */
	
		var id = (typeof(p)=='object')? p.id:p;
		var str = '';
		var pngfix = '';//(browser.cssfilter)? 'onload="utils.pngFix(this)"':'';
		var clear = '<div class="clear"></div>'; //fix for element height with floating child elements
	
		var toggle_check = 'this.previousSibling.click();utils.over(this,this.previousSibling.checked)';
		var check_on = 'if (!this.form[this.name+\'_on\'].checked) { this.form[this.name+\'_on\'].checked=true; utils.over(this.form[this.name+\'_on\'].nextSibling,1); }';
		
		switch(id)
		{
			/*	general gui
			*/
			case 'button':
			if (0) var button = {}; //dummy object for easy access in editor, can be removed in prod version
				
				var w = p.w || 18;
				str+= '<div class="button">';
				str+= '<a href="javascript://'+p.title+'" style="width:'+w+'px; background-image:url(media/button/'+p.src+'.png)"></a>';
				str+= '</div>';
				break;
				
			case 'checkbox':
			if (0) var checkbox = {};
			
				var t = p.title || '';
				var c = p.checked? ' checked':'';
				var v = p.value? ' value="'+p.value+'"':'';
				var x = p.checked? 'X':'';
				var type = p.radio? 'radio':'checkbox';
				
				str+= '<a class="check" href="javascript://select" title="'+t+'" onclick="';
				str+= '$(this).children().get(0).click();';
 				str+= '$(this).children().get(1).src = $(this).children().get(0).checked? \'media/checkboxX.png\':\'media/checkbox.png\'; this.blur()';
				str+= '">';
				str+= '<input type="'+type+'" name="'+p.name+'"'+v+c+'>';
				str+= '<img src="media/checkbox'+x+'.png">';
				str+= '<span>'+p.label+'</span>';
				str+= '</a>';
				break;

			case 'panetitle':
			if (0) var panetitle = {};
			
				str+= '<img src="media/label_'+p.title+'.png" '+pngfix+' class="pane7-title-image">';
				break;


			/*	login menu
			*/
			case 'loginform':
			if (0) var loginform = {};
			
				var preset_loginname = this.portal.dev_login || ''; //->for development, can be removed in production version
				var preset_password = this.portal.dev_login_pass || '';
	
				var login = this.portal.login.loginname || preset_loginname;
				var pass = this.portal.login.password || preset_password;
				
				str+= '<div style="margin-top:2px;">';
				str+= '<form name="loginform" method="" action="" class="loginform" onsubmit="return false">';
				str+= '<div>name:</div><input type="text" name="login" value="'+login+'">';
				str+= '<div>password:</div><input type="password" name="password" value="'+pass+'">';
				str+= '<div class="divider-straight"></div>';
				//forgot
				str+= '<div><span id="lostpassword" title="'+Locale7.get('gui','retrieve_pw')+'">forgot</span></div>';
				str+= '<div class="divider-straight"></div>';
				//remember		
				str+= '<div title="'+Locale7.get('gui','save_pw')+'">';
				str+= '<input type="checkbox" name="autologin" style="display:none">';
				str+= '<img src="media/checkbox.png" class="checkbox" style="float:left; margin:2px 4px 0px 0px;" onclick="'+toggle_check+'">';
				str+= '<span onclick="this.previousSibling.previousSibling.click();utils.over(this.previousSibling,this.previousSibling.previousSibling.checked)">remember</span>';
				str+= '</div>';
				str+= '<div class="divider-straight"></div>';
				str+= '</form>';
				str+= '</div>';
				break;

			case 'logging_in':
			if (0) var logging_in = {};
			
				str+= '<div class="loginform"><img src="media/login.gif" style="float:right; margin-right:26px; width:16px; height:16px; margin-top:2px"></div>';
				break;

			case 'logout':
			if (0) var logout = {}; 
			
				str+= '<div style="width:23px; height:18px; position:absolute; left:5px; top:1px; text-align:center; overflow:hidden; background-image:url(media/menu/bg-user-icon.png)">';
				str+= '<img id="menu-user-icon" src="media/blank.gif" style="height:16px; margin-top:1px" title="';
				str+= '">';
				str+= '</div>';
				str+= '<a href="javascript://profile" style="left:28px; width:16px; background-image:url(media/menu/expand.png)"></a>';
				str+= '<a href="javascript://logout" style="left:48px; width:18px; background-image:url(media/menu/logout.png)"></a>';
				break;


			/*	find
			*/
			case 'search':
			if (0) var search = {};
			
				var type = p.type || '';
				
				str+= '<form name="'+type+'searchform" onsubmit="return false">';
				str+= '<input name="query" type="text" class="scene-form" style="position:absolute; left:15px; top:9px; width:176px; height:17px; padding:1px 1px 1px 2px">';
				str+= '<div class="button" style="left:178px; top:12px"><a href="javascript://clear" style="width:14px; background-image:url(media/button/clear-find.png)"></a></div>';
				
				str+= this.create('result_header');
				
				if (type=='')
				{
					str+= '<div id="search-context-toggle">';
					str+= '<input type="checkbox" name="context" style="display:none" checked>';
					str+= '<img src="media/checkboxX.png" class="checkbox" style="float:left; margin:0px 5px 1px 0px;" onclick="'+toggle_check+'">';
					str+= '<span onclick="this.previousSibling.previousSibling.click();utils.over(this.previousSibling,this.previousSibling.previousSibling.checked)">';
					str+= Locale7.get('gui','find_context')+'<span id="search-context" style="font-weight:bold"></span></span>';
					str+= '</div>';
				}

				if (type=='my')
				{
 					str+= '<div id="my-search-context">';
					str+= '<div class="context">'+this.create({ id:'checkbox', radio:true, name:'context', value:'directed', label:'directed', checked:true })+'</div>';
					str+= '<div class="context">'+this.create({ id:'checkbox', radio:true, name:'context', value:'played', label:'played' })+'</div>';
					str+= '<div class="context">'+this.create({ id:'checkbox', radio:true, name:'context', value:'invited', label:'invited' })+'</div>';
 					str+= '</div>';
				}
				
				str+= '</form>';
				break;
				
			case 'result_header':
			if (0) var result_header = {};

				str+= '<div class="result-header">';
				str+= '<div class="result-count"></div><div class="result-nav"></div>';
				str+= '</div>';
				break;


			/*	scene (coverflow and lists)
			*/
			case 'scene_cover_info':
			if (0) var scene_cover_info = {};
			
				var rec = p.rec;
				var name = rec.getField('name')
					name = name.length>24? name.substring(0,24)+'..':name;
				var type = rec.getField('requiresevent')=='true'? 'multiplay':'singleplay';
				var loc = rec.getField('location') ||  Locale7.get('gui','nolocation');
				var user = rec.getField('project')=='public'? rec.getField('user'):rec.getField('project');
				if (!user) user = 'unknown';
				var shortuser = user.length>16? user.substring(0,16)+'..':user;
				var date = new Date(Number(rec.getField('creationdate'))).format('shorterhumandate');
				
				if (rec.getField('sceneiconid'))
				{
					str+= '<img class="icon" src="media/bg-scene-icon-gloss.png" style="background-image:url('+this.sceneIconUrl('small',rec)+')">';
				}
				str+= '<div class="title">';
				str+= '<div class="scene-layer-title dropshadow">'+name+'</div>';
				str+= '<div class="scene-layer-title">'+name+'</div>';
				str+= '</div>';
				str+= '<div class="meta" style="background-image:url(media/icon-list-'+type+'.png)">'+loc+'</div>';
				str+= '<div class="cover-slogan"><span class="quote">"</span>'+rec.getField('slogan').substring(0,80)+'"';
				str+= '<div class="rating">';
				str+= this.create({
						id:'rating',
						rating:(rec.getField('rating')/5)*100,
						style:'vertical-align:middle; margin-right:3px' });

				str+= '('+rec.getField('amount')+')</div>';
				str+= '</div>';
				str+= '<div class="by" title="'+user+'">'+shortuser+', '+date+'</div>';
				break;
			
			case 'scene_list_item_info':
			if (0) var scene_list_item_info = {};	

				var rec = p.rec;
				var name = rec.getField('name')
					name = name.length>24? name.substring(0,24)+'..':name;
				var user = rec.getField('user');
				var date = new Date(Number(rec.getField('creationdate'))).format('shorterhumandate');
				
				str+= '<div class="name">'+name+'</div><div class="desc">'+rec.getField('slogan').substring(0,80)+'</div><div class="by">'+user+', '+date+'</div>';
				str+= '<div class="over"></div>';
				break;

			case 'rating':
			if (0) var rating = {};
				var s = p.style? 'style="'+p.style+'"':'';
				str+= '<span class="scene-rating" '+s+'><img src="media/blank.gif" style="height:11px; width:55px;"><div class="stars on" style="width:'+p.rating+'%"></div><div class="stars off" style="width:'+(100-p.rating)+'%"></div></span>';
				break;

			default:
				if (this.scenesCreate)
				{
					/*	look in scenes Gui
					*/
					str = this.scenesCreate(p,pngfix,clear,toggle_check,check_on);
				}
				if (str=='' && this.baseUserCreate)
				{
					/*	look in base-user Gui
					*/
					str = this.baseUserCreate(p,pngfix,clear,toggle_check,check_on);
				}
				if (str=='' && this.scenesUserCreate)
				{
					/*	look in scenes-user Gui
					*/
					str = this.scenesUserCreate(p,pngfix,clear,toggle_check,check_on);
				}

				if (str=='') str = '[create failed, id='+id+']'
		}
		
		return str;
	}

	/*	init
	*/
	this.gui = new Gui(this);
}

