var Note = Class.create({
	board: null,
	width: 155,
	height: 130,
	hugeWidth: 490,
	hugeHeight: 380,
	z: 0,
	x: 0,
	y: 0,
	type: 'base', // can be base or board
	id: null,
	nick: '',
	body: '',
	color_id: 1,
	initialize: function(board,type)
	{
		this.board = board;
		this.type = type;
	},
	render: function()
	{
		// the surrounding div
		var note = new Element('div');
		this.note = note;
		if( this.id != null )
		{
			note.setAttribute('id','s'+this.id);
		}
		note.className = 'note';

		if( this.type == 'board' & this.x > this.board.right )
			this.x = this.board.right-2;

		if( this.type == 'board' & this.y > this.board.bottom )
			this.y = this.board.bottom-2;

		note.setStyle({position: 'absolute', left: this.x+'px', top: this.y+'px', zIndex: this.z});

		// shadows
		var right_shadow = new Element('div');
		right_shadow.className = 'right-shadow';

		var bottom_shadow = new Element('div');
		bottom_shadow.className = 'bottom-shadow';

		// top element, where the nickname is shown
		var top = new Element('div');
		top.className = 'top';
		if( this.linked_to == 1 )
		{
			top.insert('<a href="/board/'+this.nick+'>'+this.nick+'</a>:');
		} 
		else
		{
			top.insert(this.nick);
		}
		top.setStyle({backgroundColor: this.board.colors[this.color_id].top});
	
		// body element, where the message is shown
		var bodyEl = new Element('div');
		bodyEl.className = 'msg';
		if( this.type == 'board' )
		{
			bodyEl.insert( this.strip(this.body) );
		}
		else
		{
			bodyEl.insert( this.body );
		}
		bodyEl.setStyle({backgroundColor: this.board.colors[this.color_id].main});
	
		// bottom element, just for a nice color
		var bottom = new Element('div');
		bottom.className = 'bottom';
		bottom.setStyle({backgroundColor: this.board.colors[this.color_id].bottom});

		// append all elements
		note.insert(top);
		note.insert(right_shadow);
		note.insert(bodyEl);
		note.insert(bottom);
		note.insert(bottom_shadow);
		
		// mouse handlers
		note.observe( 'mouseenter', function(event) {
			var target = event.element();
			if( !target.hasClassName( 'note' ) )
				target = target.up('.note');

			if (Draggables.activeDraggable == null && this.board.allow_drag ){
				if( this.type == 'board' ) // show the menu
					target.firstChild.appear({duration: .2});

				target.setStyle({zIndex: this.board.max_zIndex});
			}
		}.bind(this));

		note.observe( 'mouseleave', function(event) {
			var target = event.element();
			if( !target.hasClassName( 'note' ) )
				target = target.up('.note');

			if (Draggables.activeDraggable == null && this.board.allow_drag ){ // if no drag takes place
				if( this.type == 'board' ) // hide the menu
					target.firstChild.fade({duration: .2});

				target.setStyle({zIndex: this.z});
			}
		}.bind(this));
	
		this.make_note_draggable(note);
	
		if( this.type == 'board' )
		{
			// parse smileys
			this.smileys();

			// get youtube vids	
			this.youtube();
		
			// insert the note into the board
			this.board.board.insert(note);
		}
		else
		{
			this.board.base.insert(note);
		}

		// get dimensions
		this.width = note.getWidth();
		this.height = note.getHeight();

		// create the menu 
		if( this.type == 'board' )
		{
			this.create_menu();
		}
		
		return note;
	},
	setZ: function(z)
	{
		this.note.setStyle({zIndex: z});
		this.z = z;
	},
	getBody: function()
	{
		return this.note.down('.msg');
	},
	strip: function(txt)
	{
		var allowedTags = new Array(
			'i','b','a','img','embed','object','h1','h2','h3','h4','h5','h6','param'
		);
		var allowedAttributes = new Array(
			'href','src','alt','name','value','height','width','type','allowscriptaccess','allowfullscreen'
		);
		var i=0;

		// remove { and } because these chars mark correct tags later
		txt = txt.replace(/\{/,'<').replace(/\}/,'>');

		while( i<txt.length )
		{
			var tagStart = txt.indexOf('<');
			var tagStop = txt.indexOf('>');

			if( tagStart == -1 || tagStop == -1 )
			{
				// no occurence of complete tags.
				break;
			}

			var okayTag = true;
			var okayAttribute = true;
			var parts = txt.substring(tagStart+1,tagStop).split(/ +/);
			var currentTag = parts.shift().replace(/\//,'');

			if( allowedTags.indexOf(currentTag) < 0 )
			{
				okayTag = false;
			}

			if( parts.length > 0 )
			{
				// there are attributes
				for( var p=0; p<parts.length; p++ )
				{
					parts[p] = parts[p].replace(/=".*?"/,'');
					if( allowedAttributes.indexOf(parts[p]) < 0 && parts[p] != '/') // trailing slash is allowed
					{
						okayAttribute = false;
					}
				}
			}
			if( okayTag && okayAttribute )
			{
				txt = txt.replace(/</, '{').replace(/>/,'}')
			}
			else
			{
				// no match, escape
				txt = txt.replace(/</,'&lt;').replace(/>/,'&gt;');
			}

			i = tagStop+1;
		}
		txt = txt.replace(/</g,'&lt;').replace(/>/g,'&gt;');
		txt = txt.replace(/{/g, '<').replace(/}/g, '>');

		// last but not least, remove javascript href's
		txt = txt.replace(/(href=["|']) *javascript:/, '$1');

		return txt;
	},
	smileys: function() // parse smileys and show the images
	{
		var smileys = new Hash({
			':-)': 'smile',
			':-D': 'biggrin',
			':-(': 'sad',
			':-|': 'neutral',
			':-O': 'surprised',
			';-)': 'wink',
			'8-)': 'cool',
			':)': 'smile',
			':D': 'biggrin',
			':(': 'sad',
			':|': 'neutral',
			':O': 'surprised',
			';)': 'wink',
			'8)': 'cool'
		});
		var body = this.getBody();
		var i = 0;
		smileys.each(function(smiley)
		{
			// strip regexp chars from smileys
			var from = smiley.key.replace(/\)/, '\\\)').replace(/\(/,'\\\(').replace(/\|/,'\\\|');
			var to = '<img src="/images/icon_'+smiley.value+'.gif"/>';
			var regExp = new RegExp( from, 'gi' );
			body.innerHTML = body.innerHTML.replace(regExp, to);
			i++;
		}.bind(this));
	},
	youtube: function() // parse youtube video and show thumbnail on small notes. 
	{
		var objects = this.note.getElementsByTagName('object');
		var body = this.note.down('.msg');

		this.youtubes = new Array();

		for( var i=0; i<objects.length; i++ )
		{
			var youtube = null;

			// first use the object. in IE the embed is not in the DOM for some reason
			var object = $(objects[i]);
			var parms = object.getElementsByTagName('param');

			for( p=0; p<parms.length; p++ )
			{
				// search for movie parameter
				if( parms[p].getAttribute('name') == 'movie' )
				{
					// get the source of the movie
					youtube = new Youtube( parms[p].getAttribute('value') );
					break;
				}
			}

			// this is needed for chrome, why o why?:
			youtube.width = object.getAttribute('width');
			youtube.height = object.getAttribute('height');

			// insert thumbnail
			object.insert( {after: youtube.get_thumb()} );

			// remove the object completely. This is needed for IE and Chrome
			object.remove();

			youtube.thumb_clicked = function()
			{
				this.resize(true);
			}.bind(this);
			
			this.youtubes.push(youtube);
		}
	},
	// TODO: turn the fucking youtube movie into a object
	toggle_objects: function( show )
	{
		if( show )
			this.youtubes[0].show();

		return;

		

		var objects = this.note.getElementsByTagName('object');
		var body = this.note.down('.msg');

		for( var i=0; i<objects.length; i++ )
		{
			var object = $(objects[i]);
			var parms = object.childNodes;
			if( show )
			{
				body.down('.yt-img').hide();
				object.show();
	
				// show object with resize
				var geom = object.getAttribute('lastGeom').split('x');
				object.setStyle({width: geom[0]+'px', height: geom[1]+'px'});

				var embed = object.down('embed');

				// remove autoplay and add it
				embed.setAttribute('src', embed.getAttribute('src').replace(/&autoplay=1/,'') + '&autoplay=1');
				for( p=0; p<parms.length; p++ )
				{
					if( parms[p].getAttribute('name') == 'movie' )
					{
						// remove autoplay from object and add it again
						parms[p].setAttribute('src', parms[p].getAttribute('value').replace(/&autoplay=1/,'') + '&autoplay=1' );
						break;
					}
				}
			}
			else
			{
				body.down('.yt-img').show();
				object.hide();

				object.setStyle({width: '0px', height: '0px'});
				var embed = object.down('embed');

				// trying for IE. is not working
				embed.setStyle({width: '0px', height: '0px'});
				embed.setAttribute('width', 0);
				embed.setAttribute('height', 0);
				embed.hide();
				
				//remove autoplay from embed
				embed.setAttribute('src', embed.getAttribute('src').replace(/&autoplay=1/,''));

				for( p=0; p<parms.length; p++ )
				{
					if( parms[p].getAttribute('name') == 'movie' )
					{
						// remove autoplay from object
						parms[p].setAttribute('src', parms[p].getAttribute('value').replace(/&autoplay=1/,''));
						break;
					}
				}
			}
		}
	},
	resize: function( grow )
	{
		if( grow )
		{
			// Make the note big
			this.note.setStyle({zIndex: this.board.max_zIndex});
			new Effect.Move( this.note, {
				x: (this.board.width / 2) + this.board.left - (this.hugeWidth / 2), 
				y: (this.board.height / 2) + this.board.top - (this.hugeHeight / 2), 
				duration: .5, 
				mode: 'absolute'
			});
			new Effect.Tween( null, this.width, this.hugeWidth, {duration: .5}, function(p){
				this.note.setStyle( {width: p + 'px'} );
			}.bind(this));
			new Effect.Tween( 
				null, 
				this.height, 
				this.hugeHeight, 
				{
					duration: .5,
					afterFinish: function(){
						this.maximize.setAttribute('src', '/images/resize-down.png');
						this.maximize.title = 'Minimize this note';
						this.youtubes.each(function(youtube)
						{
							youtube.show();
						});
						//this.toggle_objects( true );
					}.bind(this)
				}, 
				function(p){
					this.note.setStyle( {height: p + 'px'} );
				}.bind(this)
			);
			this.board.allow_drag = false;

			// this resized note can not be dragged, so remove observer
			Event.stopObserving(this.draggable.handle, 'mousedown', this.draggable.eventMouseDown);
		}
		else
		{
			// Make the note small
			this.board.allow_drag = true;
			this.note.setStyle({zIndex: this.z});
			new Effect.Move( this.note, {x: this.x, y: this.y, duration: .5, mode: 'absolute'} );
			new Effect.Tween( null, this.hugeWidth, this.width, {duration: .5}, function(p){
				this.note.setStyle( {width: p + 'px'} );
			}.bind(this));
			new Effect.Tween( null, this.hugeHeight, this.height, {duration: .5}, function(p){
				this.note.setStyle( {height: p + 'px'} );
			}.bind(this));

			this.maximize.setAttribute('src', '/images/resize-up.png');
			this.maximize.title = 'Maximize this note';
			this.youtubes.each(function(youtube)
			{
				youtube.hide();
			});

			// retach observer
			Event.observe(this.draggable.handle, 'mousedown', this.draggable.eventMouseDown);
		}
	},
	create_menu: function( startVisible )
	{
		var menu = new Element('div');
		menu.className = 'menu';
		menu.setStyle({
			marginTop: '-12px', marginRight: '3px', 
			cssFloat: 'right', height: '12px', width: '50px', backgroundColor: 'transparent'
		});

		if( startVisible )
		{
			menu.show();
		}
		else
		{
			menu.hide();
		}

		this.maximize = new Element('img', {src: '/images/resize-up.png', alt: '+'});
		this.maximize.title = 'Maximize this note';

		this.maximize.observe('click', function()
		{
			if( !this.board.allow_drag )
			{
				this.resize( false );
			}
			else
			{
				this.resize( true );
			}
		}.bind(this));
		menu.insert(this.maximize);

		var remove = new Element('img', {src: '/images/delete.png', alt: 'x'});
		menu.insert(remove);
		remove.hide();

		remove.title = 'Remove this note completely';
	
		remove.observe('click', function( event ) 
		{
			var element = Event.element(event);
			this.board.allow_drag = true;

			if( this.has_form() )
			{
				// just remove the note from the screen
				this.note.shrink({duration: .5});
				return true;
			}

			var parms = new Hash();
			parms.set('id', this.id);

			if ( parms.get('id') <=0 )
				return;

			// send delete
			new Ajax.Request(this.board.get_board_url(), {
				method: 'delete', 
				parameters: parms,
				onSuccess: function(transport) {
					this.note.shrink({
						onFinish: function()
						{
							this.remove();
						}.bind(this)
					});
				}.bind(this)
			});
			return false;

		}.bind(this));

		this.remove_button = remove;

		this.note.firstChild.insert({before: menu});
	},
	get_element: function()
	{
		return this.note;
	},
	make_note_draggable: function(note) {
		if (this.board.allow_move || this.type == 'base') {
			this.draggable = new Draggable( note, {scroll:window, handle:false, revert:false, starteffect:false, endeffect:false,
				snap: function(x,y) {
					return[
		       				x<this.board.right-2 ? (x > this.board.left ? x : this.board.left ) : this.board.right-2,
		       				y<this.board.bottom-2 ? (y > this.board.top ? y : this.board.top ) : this.board.bottom-2
					];
		   		}.bind(this),
				onStart: function(draggable) {
					var element = draggable.element;
	
					if( this.type == 'base' ){
						// if base note is dragged, create a new one to put into the base again
						baseNote = new Note(this.board, 'base');
						baseNote.color_id = this.color_id;
						baseNote.nick = 'Drag me!';
						baseNote.body = 'and write a message!';
						baseNote.z = this.z;
						baseNote.x = this.x;
						baseNote.y = this.y
						baseNote.render();

						// set an explanation text.	
						element.getElementsByClassName('msg')[0].innerHTML = 'Drop me!';
					}

					element.setStyle({opacity: 0.8});

					if (this.board.raise) {
						//note.setStyle({left: });
					}
				}.bind(this),
				onEnd: function(draggable){
					var element = draggable.element;
					var delta = draggable.currentDelta();
				
					this.x = delta[0]
					this.y = delta[1];
					
					this.setZ( this.board.max_zIndex );

					if (this.board.raise) {
						/*element.getElementsByClassName('right-shadow')[0].style.width = '3px';
						element.getElementsByClassName('bottom-shadow')[0].style.height = '3px';
						element.style.paddingTop = '2px';
						element.style.paddingRight = '2px';*/
					}

					// storing a move is not allowed if form is shown.
					if( this.type == 'board' && !this.has_form() )
					{ 
						var parms = new Hash();
					
						parms.set('id', element.getAttribute('id').replace(/s/, ''));
						parms.set('x', this.x-this.board.left);
						parms.set('y', this.y-this.board.top);

						new Ajax.Request(this.board.get_board_url(), {
							method: 'post', 
							parameters: parms
						});
					}
					else if( this.type == 'base' )
					{
						var msg = element.getElementsByClassName('msg')[0];
						msg.removeChild( msg.firstChild );
						// this note is now on the board
						this.type = 'board';
						this.create_menu(true);
						this.board.allow_drag = false;
						this.create_form();
					}

					// raise the max index, because we are going higher!
					this.board.max_zIndex++;

					element.setStyle({opacity: 1});

					return true;
				}.bind(this)}
			);
		}
		return true;
	},
	create_login_form: function()
	{
		var body = this.getBody();
		body.setStyle({paddingLeft: '85px', paddingTop: '200px'});
		body.insert('<h2>Fill in this form to login</h2><h1>E-Mail Address:</h1>');

		var mail = new Element('input');
		mail.setAttribute('type','text');
		mail.className = 'login';

		body.insert(mail);
		body.insert('<h1>Password:</h1>');

		var pass = new Element('input');
		pass.setAttribute('type','password');
		pass.className = 'login';

		body.insert(pass);

		var loginButton = new Element('input');
		loginButton.setAttribute('type','button');
		loginButton.value = 'Login!';
		loginButton.className = 'login';

		body.insert('<br/><br/>');
		body.insert(loginButton);
		
		mail.focus();

		pass.observe('keyup', function(event)
		{
			if( event.keyCode == Event.KEY_RETURN )
			{
				this.send_login(mail.value, pass.value);
			}
		}.bind(this));

		loginButton.observe('click', function()
		{
			this.send_login(mail.value, pass.value);
		}.bind(this));
	},
	send_login: function( mail, pass )
	{
		var parms = new Hash();
		parms.set('mail', mail);
		parms.set('pass', hex_md5(pass) );
		new Ajax.Request(this.board.get_login_url(), {
			method: 'post',
			parameters: parms,
			onSuccess: function( transport )
			{
				this.board.render_login( transport );
				this.board.allow_drag = true;
				this.note.shrink({duration: .5, afterFinish: function(){this.remove();}.bind(this)});
			}.bind(this),
			onFailure: function()
			{
				this.getBody().insert('<h2>Login failed, please try again</h2>');
			}.bind(this)
		});
	},
	remove: function()
	{
		this.note.remove();
		this.on_remove();
	},
	on_remove: function(){},
	has_form: function() {
		var msg = this.note.getElementsByClassName('msg')[0];

		if( msg.down('textarea') )
		{
			return true;			
		}

		return false;
	},
	create_form: function() {
		var nickElement = this.note.getElementsByClassName('top')[0];
		nickElement.removeChild(nickElement.firstChild);
		nickElement.title = 'Your name here';

		var msgElement = this.note.getElementsByClassName('msg')[0];
		msgElement.style.overflow = 'hidden';
		msgElement.title = 'Your message here. Some HTML is allowed. Also embedded YouTube video\'s';

		if (!this.board.from_screenname) {
			var nickTxt = new Element('input');
			nickTxt.setAttribute('type', 'text');
			nickTxt.value = 'name...';
			nickTxt.setAttribute('name', 'nick');
			nickElement.insert(nickTxt);
		} else {
			var nickLink = new Element('a', {href: 'http://youstickit.com/board/'+this.board.from_screenname});
			nickLink.update(this.board.from_screenname+':');
			nickElement.insert(nickLink);
			nickElement.insert(new Element('br'));
		}

		var msgWrapper = new Element('div');
		msgWrapper.className = 'wrapper';

		msgField = new Element('textarea');
		msgField.setAttribute('name', 'message');
		msgWrapper.insert(msgField);
		msgElement.insert(msgWrapper);

		var buttons = new Element('div');
		buttons.className = 'buttons';
		msgElement.insert(buttons);

		var submitBut = new Element('input');
		submitBut.setAttribute('type', 'submit');
		submitBut.setAttribute('name', 'submit');
		submitBut.setAttribute('value', 'Stick it!');
		submitBut.title = 'Stick this note!';
		buttons.insert(submitBut);

		var drawLink = new Element('a');
		drawLink.setAttribute('href', '#');
		drawLink.update('DRAW!');
		drawLink.title = 'Add a drawing to this note with YouDrawIt!';
		buttons.insert(drawLink);

		var youDrawIt = new YouDrawIt();
		youDrawIt.setOutputElement( msgField );
		youDrawIt.setOutputType('HTML');
		youDrawIt.setInputGeometry('20x20');
		youDrawIt.setWindowType('window');

		drawLink.observe( 'click', function(event) {
			youDrawIt.openWindow();
			return false;
		});

		submitBut.observe( 'click', function(event) {
			if (msgField.value.length <= 0) {
				msgField.focus();
				return false;
			}
			if (!this.board.from_screenname) {
				if (nickTxt.value.length <= 0) {
					nickTxt.focus();
					return false;
				}
			}
			submitBut.disable();
			submitBut.value = 'saving..';
			var parms = new Hash();
			if (!this.board.from_screenname) {
				parms.set('nick', nickTxt.value);
				parms.set('boardlogin', true);
			} else {
				parms.set('nick', this.board.from_screenname);
			}
			parms.set('body', msgField.value);
			parms.set('color_id', this.color_id);
			parms.set('x', this.note.offsetLeft - this.board.left);
			parms.set('y', this.note.offsetTop - this.board.top);
			new Ajax.Request(this.board.get_board_url(), {
				method: 'post',
				parameters: parms,	
				onSuccess: function(transport) {
					var note = transport.responseXML.getElementsByTagName('note');
					note = note[0];
					var id = note.getAttribute('id');
					var nick = note.getElementsByTagName('nick');
					nick = nick[0];
					var body = note.getElementsByTagName('body');
					body = body[0];
					this.note.setAttribute('id', 's'+id);	
					msgElement.innerHTML = body.firstChild.data;
					nickElement.innerHTML = nick.firstChild.data;

					var newNote = new Note(this.board, 'board');
					newNote.id = id;
					newNote.color_id = this.color_id;
					newNote.nick = nick.firstChild.data;
					newNote.body = body.firstChild.data;
					newNote.x = Math.round(note.getAttribute('x')) + this.board.left;
					newNote.y = Math.round(note.getAttribute('y')) + this.board.top;
					newNote.z = this.board.max_zIndex;
					newNote.render();

					this.board.max_zIndex++;
					this.board.notes.push(newNote);
					this.board.allow_drag = true;
					this.note.remove();
					this.note = newNote.note;

					this.board.on_stick( newNote );

				}.bind(this)
			});
		}.bind(this));

		this.remove_button.show();

		if( !this.board.from_screenname ){
			nickTxt.focus();
			nickTxt.select();
		} else {
			msgField.focus();
			msgField.select();
		}
	}
});

var Board = Class.create( {
	max_zIndex: 0,
	notes: new Array(),
	allow_move: true,
	raise: false,
	from_screenname: false,
	note_width: 155,
	note_height: 130,
	last_modified: null,
	colors: new Array(),
	url: null,
	screenname: null,
	format: 'xml',
	loginNote: undefined,
	login_element: undefined,
	online_element: undefined,
	allow_drag: true,
	verify_login: true,
	initialize: function(board, base) {
		//alert(navigator.appVersion);
		this.board = $(board);
		this.base = $(base);
		/*if (document.viewport.getWidth() < 1005 || document.viewport.getHeight() < 600) {
			var warning = new Element('div');
			warning.setStyle({'float': 'left', color: 'red'});
			warning.insert(' - The size of this window is not optimal. If you are the owner of this board, please update your popup scripts.');
			this.board.parentNode.insert(warning);
		}*/

		this.left = this.board.cumulativeOffset()[0];
		this.top = this.board.cumulativeOffset()[1];

		this.width = this.board.getWidth();
		this.height = this.board.getHeight();

		this.right = this.left + this.width - this.note_width;
		this.bottom = this.top + this.height - this.note_height;
		this.show_loading();
	},
	show_login: function() {
		if( !this.loginNote )
		{
			loginNote = new Note(this, 'board');
			loginNote.height = 0;
			loginNote.width = 0;
			loginNote.nick = 'Login';
			loginNote.color_id = 2;
			loginNote.x = this.right+162;
			loginNote.y = this.bottom-100;
			loginNote.z = 1000;
			loginNote.render();
			loginNote.resize(true);
			loginNote.create_login_form();
			this.loginNote = loginNote;
			this.loginNote.on_remove = function()
			{
				this.loginNote = undefined;				
			}.bind(this);
		}
	},
	show_loading: function() {
		this.loading_window = new Element('div');
		var loading_image = new Element('img', {src: '/images/throbber-fast.gif'});
		this.loading_window.insert(loading_image);
		this.loading_window.insert('Loading...');
		this.loading_window.setStyle( {position: 'absolute', left: '300px', top: '200px', 
		zIndex: 600, backgroundColor: 'white', border: '2px solid', padding: '10px', font: '20pt Verdana'} );
		this.board.insert(this.loading_window);
	},
	hide_loading: function() {
		this.board.removeChild(this.loading_window);
	},
	get_note_by_id: function(id) {
		for( var i=0; i<this.notes.length; i++ )
		{
			if( this.notes[i].id == id )
			{
				return this.notes[i];
			}
		}
		return false;
	},
	on_stick: function( note )
	{

	},
	handle_request: function( transport )
	{
		var board = transport.responseXML.getElementsByTagName('board')[0];
		var theme = board.getElementsByTagName('theme')[0];
		var colors = theme.getElementsByTagName('color');
		var online = board.getElementsByTagName('online');

		if( this.online_element )
		{
			this.online_element.update(''); // TODO only refresh when needed

			for( var i=0; i<online.length; i++ )
			{
				var screenname = online[i].firstChild.data;
				if( screenname == 'Anonymous' )
				{
					this.online_element.insert('- ' + screenname + '<br/>');
				}
				else
				{
					this.online_element.insert('- <a href="/board/' + screenname + '">' + screenname + '</a><br/>');
				}
			}
		}
		
		for( var i=0; i<colors.length; i++ )
		{
			var colorHash = new Object({
				top: colors[i].getAttribute('top'), 
				bottom: colors[i].getAttribute('bottom'), 
				main: colors[i].firstChild.data
			});
			this.colors[colors[i].getAttribute('id')] = colorHash;	
		}

		this.last_modified = board.getAttribute('modified');
	
		var notes = board.getElementsByTagName('note');

		// reverse the order of the array
		var revNotes = new Array();
		var count=0;
		for( var i=notes.length-1; i>=0; i-- )
		{
			revNotes[count] = notes[i];
			count++;
		}

		for( var i=0; i<revNotes.length; i++ )
		{
			var note = revNotes[i];
			var x = Math.round(note.getAttribute('x')) + this.left;
			var y = Math.round(note.getAttribute('y')) + this.top;
			var id = note.getAttribute('id');
			var linked_to = note.getAttribute('linked_to');

			if( note.getAttribute('status') )
			{
				// check for updated notes
				if( note.getAttribute('status') == 'updated' )
				{
					updatedNote = this.get_note_by_id( id );
					if( updatedNote )
					{
						if( updatedNote.x != x || updatedNote.y != y )
						{
							updatedNote.setZ(this.max_zIndex);
							this.max_zIndex++;
							new Effect.Move( updatedNote.note, {x: x, y: y, duration: .5, mode: 'absolute'} );
						}

						// go to next iteration. we don't want this note to be created again.
						continue;
					}
				}
				else if( note.getAttribute('status') == 'created' )
				{
					newNote = this.get_note_by_id( id );
					if( newNote )
					{
						// go to next iteration. this note already exists.
						continue;
					}
				} 
				else if( note.getAttribute('status') == 'deleted' )
				{
					newNote = this.get_note_by_id( id );
					if( newNote )
					{
						if( newNote.note ) // check for internal element
						{
							newNote.note.shrink();
						}
						continue;
					}
				}
			}

			var nick = '';
			var body = '';
			var color_id = note.getAttribute('colorid');

			for( var n=0; n<note.childNodes.length; n++ )
			{
				if( note.childNodes[n].tagName == 'nick' )
				{
					{
						nick = note.childNodes[n].firstChild.data;
					}
				}
				
				if( note.childNodes[n].tagName == 'body' )
				{
					if( note.childNodes[n].firstChild )
					{
						body = note.childNodes[n].firstChild.data;
					}
				}
			}

			var newNote = new Note(this,'board');
			newNote.id = id;
			newNote.linked_to = linked_to;
			newNote.color_id = color_id;
			newNote.x = x;
			newNote.y = y;
			newNote.nick = nick;
			newNote.body = body;
			newNote.z = this.max_zIndex;
			newNote.render();

			this.notes.push( newNote );
			this.max_zIndex++;
		}
	},
	get_verify_url: function()
	{
		return this.url+'/account/verify.xml';
	},
	get_login_url: function()
	{
		return this.url+'/account/login.xml';
	},
	get_logout_url: function()
	{
		return this.url+'/account/logout.xml';
	},
	get_board_url: function()
	{
		return this.url+'/board/'+this.screenname+'.xml';
	},
	render_login: function( transport )
	{
		if( !this.login_element )
		{
			return false;
		}
		if( transport ) // user is logged in
		{
			var account = transport.responseXML.getElementsByTagName('account')[0];
			var screenname = account.getAttribute('screenname');

			this.from_screenname = screenname;

			this.login_element.update('');
			this.login_element.insert('<b>Logged in as:</b> <a href="/board/'+
			screenname+'">' + screenname + '</a><br />');

			var manage = new Element('a', {href: '/settings.php'});
			manage.insert('<img src="/images/preferences-system.png" style="border: none;" /> Settings');
			this.login_element.insert(manage);
			this.login_element.insert('<br/>');

			var logout = new Element('a', {href: '/logout.php'});
			logout.insert('<img src="/images/gnome-logout.png" style="border: none;" /> Logout');
			logout.observe('click', function(event)
			{
				new Ajax.Request(this.get_logout_url(), {
					method: 'post',
					onSuccess: function( transport )
					{
						this.render_login(null);
					}.bind(this)
				});
				event.stop();
			}.bind(this));
			this.login_element.insert(logout);


			// show remove button if correct user
			if( screenname == this.screenname )
			{
				this.notes.each(function(note)
				{
					note.remove_button.show();
				});
			}
		}
		else // user is not logged in
		{
			this.login_element.update('');
			this.login_element.insert(new Element('b').insert('Not logged in!<br/>'));
			var login = new Element('a', {href: '#'});
			login.insert('<img src="/images/gohome.png" style="border: none;"/> Login');
			login.observe('click', function(event)
			{
				this.show_login();
				event.stop();
			}.bind(this));
			this.login_element.insert(login);

			// hide remove button
			this.notes.each(function(note)
			{
				note.remove_button.hide();
			});
		}
	},
	render: function() 
	{
		// get notes
		new Ajax.Request( this.get_board_url(), {
			method: 'get',
			onSuccess: function( transport )
			{
				this.handle_request( transport );
				this.load_base_notes();
				this.hide_loading();
				// verify login
				if( this.verify_login )
				{
					new Ajax.Request( this.get_verify_url(), {
						method: 'get',
						onSuccess: function( transport )
						{
							this.render_login(transport);
						}.bind(this),
						onFailure: function()
						{
							this.render_login(null);
						}.bind(this)
					});
				}
			}.bind(this)
		});	
	},
	load_base_notes: function()
	{
		for( var i=0; i<3; i++ )
		{
			var baseNote = new Note(this, 'base');
			baseNote.nick = 'Drag me';
			baseNote.body = 'and write a message!';
			baseNote.z = i;
			baseNote.x = this.base.cumulativeOffset()[0]+5;
			baseNote.y = this.base.cumulativeOffset()[1]+(i*50);
			baseNote.color_id = i+1;
			baseNote.render();
		}
	},
	start_updater: function() {
		var parms = new Hash();
		setInterval( function() {
			parms.set('gt', this.last_modified);
			new Ajax.Request( this.get_board_url(), {
				method: 'get',
				parameters: parms,
				onSuccess: function( transport )
				{
					this.handle_request( transport );

				}.bind(this)
			});
		}.bind(this), 5000 );
	},
	toggle_history_slider: function (on) {
		if (on) {
			this.board.setStyle({overflow: 'auto'});
		} else {
			this.board.setStyle({overflow: 'hidden'});
		}
		var notesArray = new Array();
		for (var i=1; i<this.notes.length; i++) {
			notesArray[parseInt(this.notes[i].getAttribute('id').substring(1))] = this.notes[i];
		}
		notesArray.sort( function(a,b){ return a-b; } );
		notesArray.each( function(item) {
			if( item != undefined )
			{
				if( on ) {
					item.setStyle({position: 'static', cssFloat: 'left'});
				} else {
					item.setStyle({position: 'absolute', cssFloat: 'none'});
				}
				//new Effect.Scale(item, 150, {duration: 2.0});
			}
		});
	}
});
