////////////////// MyStickies //////////////////////////////

MyStickies = window.MyStickies || {};
MyStickies = {
	local: MyStickies.local || false,
	disabled: MyStickies.disabled || false,
	loadUrl: MyStickies.loadUrl || 'http://www.mystickies.com/',
	url: MyStickies.url || 'http://www.mystickies.com/',
	defaultColor: '#FEF49C',
	defaultWidth: 200,
	defaultHeight: 200,
	defaultX: 200,
	defaultY: 200,
	minHeight: 40,
	minWidth: 40,
	startingZIndex: 100,
	tmpId: 1,
	username: MyStickies.username || '',
	password: MyStickies.password || '',
	viewHelp: MyStickies.viewHelp || false,
	loader: MyStickies.loader || false,
	loaded: MyStickies.loaded || false,
	Prefs: MyStickies.Prefs || {},
	colors: ['#FEF49C', // YELLOW
			'#B2FFA1', // GREEN
			'#ADF4FF', // BLUE
			'#FFC7C7', // PINK
			'#B6CAFF', // PURPLE
			'#EEEEEE'], // GRAY
	
	login: function(username, password) {
		try {
		if (username.length) {
			this.username = username;
			this.password = password;
			MyStickies.Stack.clearNotes();
			MyStickies.Stack.loadNotes();
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	load: function() {
		try {
		if (this.disabled) return;
		MyStickies.loaded = true;
		MyStickies.utils.attachStyles();
		MyStickies.utils.fixFlash();
		MyStickies.Stack.loadNotes();
		if (MyStickies.viewHelp) MyStickies.displayHelp();
		MyStickies.Event.addListener(document, 'mousedown', this, this.startDrawNote);
		MyStickies.Event.addListener(document, 'selectstart', this, this.cancelSelection);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	cancelSelection: function(e) {
		try {
		if (e.altKey) {
			e.stop();
			return false;
		}
		if (this.dontSelect) {
			this.dontSelect = false;
			e.stop();
			return false;
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	stopAlt: function(e) {
		e.stop();
		MyStickies.Event.removeListener(document, 'keyup', MyStickies.stopAlt);
	},
	
	startDrawNote: function(e) {
		try {
		if (!e.altKey) return;
		// stop the alt action onkepup
		MyStickies.Event.addListener(document, 'keyup', this.stopAlt);
		
		var str = '';
		if (window.getSelection) str += window.getSelection();
	    else if(document.selection && document.selection.createRange) {
			var range = document.selection.createRange();
			str += range.text;
		}
		
		e.preventDefault();
		this.drawBox = document.createElement('div');
		this.drawBox.appendChild(document.createElement('div'));
		this.drawBox.x = e.pageX;
		this.drawBox.y = e.pageY;
		this.drawBox.str = str;
		var st = this.drawBox.style;
		this.drawBox.className = 'ms_dragBox';
		st.left = e.pageX + 'px';
		st.top = e.pageY + 'px';
		st.width = '0px';
		st.height = '0px';
		document.body.appendChild(this.drawBox);
		MyStickies.Event.addListener(document, 'mousemove', this, 'drawNote');
		MyStickies.Event.addListener(document, 'mouseup', this, 'endDrawNote');
		return false;
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	drawNote: function(e) {
		try {
		var st = this.drawBox.style;
		var x1 = this.drawBox.x;
		var y1 = this.drawBox.y;
		var x2 = e.pageX;
		var y2 = e.pageY;
		st.left = Math.min(x1, x2) + 'px';
		st.top = Math.min(y1, y2) + 'px';
		st.width = Math.abs(x1 - x2) + 'px';
		st.height = Math.abs(y1 - y2) + 'px';
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	endDrawNote: function(e) {
		try {
		if (this.drawBox)
			document.body.removeChild(this.drawBox);
		var st = this.drawBox.style;
		this.addNote(parseInt(st.left), parseInt(st.top), parseInt(st.width), parseInt(st.height), this.drawBox.str);
		MyStickies.Event.removeListener(document, 'mousemove', this, 'drawNote');
		MyStickies.Event.removeListener(document, 'mouseup', this, 'endDrawNote');
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	addNote: function(x, y, width, height, content) {
		try {
		if (this.disabled) return;
		var note = new MyStickies.Note(MyStickies.tmpId++);
		MyStickies.Stack.add(note, true);
		if(content)
			note.setText(content);
		if (x && y) note.move(x, y);
		if (width && height) note.setSize(width, height);
		// some img problems when done right away
		setTimeout(function(){note.save();}, 100);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	enable: function() {
		try {
		if(!MyStickies.disabled) return;
		if (!document.getElementById('ms_css')) MyStickies.attachStyles();
        if (!MyStickies.menuDisabled) MyStickies.Menu.create();
		MyStickies.Stack.loadNotes();
		MyStickies.disabled = false;
		MyStickies.Event.addListener(document, 'mousedown', this.startDrawNote);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	disable: function() {
		try {
		MyStickies.Stack.clearNotes();
        MyStickies.Menu.remove();
		MyStickies.disabled = true;
		MyStickies.Event.removeListener(document, 'mousedown', this.startDrawNote);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	savePage: function() {
		try {
		MyStickies.Stack.saveNotes();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	displayHelp: function() {
		try {
		var help = new MyStickies.Help();
		document.body.appendChild(help);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
};

//////////////// Utilities ///////////////////////////////

MyStickies.utils = {
	extend: function(destination, source) {
		try {
		for (property in source) {
			destination[property] = source[property];
		}
		return destination;
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	changeShade: function(hex, percent, noSatChange) {
		try {
		// make this a lower luminosity
		var hex = parseInt("0x" + hex.substring(1,7));
		var r, g, b, c, m, y, k, l;
		r = hex >> 16 & 0xFF;
		g = hex >> 8 & 0xFF;
		b = hex >> 0 & 0xFF;
		var hsl = this.RGBtoHSL(r, g, b);
		if (!noSatChange) hsl[1] += (1 - hsl[1])*(1 - percent);
		hsl[2] *= percent;
		var rgb = this.HSLtoRGB(hsl[0], hsl[1], hsl[2]);
		r = this.numToHex(rgb[0]);
		g = this.numToHex(rgb[1]);
		b = this.numToHex(rgb[2]);
		return "#" + r + g + b;
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	numToHex: function(number) {
		var str = Math.round(number).toString(16);
		if (str.length == 0) return '00';
		else if (str.length == 1) return '0' + str;
		else if (str.length > 2) return 'ff';
		else return str;
	},
	
	RGBtoHSL: function(R, G, B) {
		var min, max, delta, H, S, L, del_R, del_G, del_B;
		R = R/255;
		G = G/255;
		B = B/255;
		
		min = Math.min(R, G, B);
		max = Math.max(R, G, B);
		delta = max - min;
		L = (R+G+B)/3; // Luminosity
		if (max == 0) { // gray
			H = 0;
			S = 0;
		} else { // some color
			if (L < 0.5) S = delta/(max + min);
			else S = delta/(2 - max - min );
			
			del_R = (((max - R)/6) + (delta/2))/delta;
			del_G = (((max - G)/6) + (delta/2))/delta;
			del_B = (((max - B)/6) + (delta/2))/delta;
			
			if      (R == max) H = del_B - del_G;
			else if (G == max) H = 1/3 + del_R - del_B;
			else if (B == max) H = 2/3 + del_G - del_R;
			
			if (H < 0) H += 1;
			if (H > 1) H -= 1;
		}
		return [H, S, L];
	},
	
	HSLtoRGB: function(H, S, L) {
		var var1, var2;
		if (S == 0) {
			R = L*255;
			G = L*255;
			B = L*255;
		} else {
			if (L < 0.5) var2 = L*(1 + S);
			else         var2 = (L + S) - (S * L);
			
			var1 = 2*L - var2;
			
			function Hue_2_RGB(v1, v2, vH) {
				if (vH < 0) vH += 1
				if (vH > 1) vH -= 1
				if ((6*vH) < 1) return v1 + (v2 - v1)*6*vH;
				if ((2*vH) < 1) return v2;
				if ((3*vH) < 2) return v1 + (v2 - v1)*((2/3) - vH)*6;
				return v1;
			}
			
			R = 255*Hue_2_RGB(var1, var2, H + (1/3));
			G = 255*Hue_2_RGB(var1, var2, H);
			B = 255*Hue_2_RGB(var1, var2, H - (1/3));
		}
		return [Math.round(R), Math.round(G), Math.round(B)];
	},
	
	createDOMClass: function(element, parentName, classPrefix) {
		try {
		return function() {
			// this allows selects and tables to be worked with
			var div, elem, name, prop;
			div = document.createElement('div');
			div.innerHTML = element;
			elem = div.firstChild;
			for (prop in this) {
				elem[prop] = this[prop];
			}
			tags = elem.getElementsByTagName('*');
			for (var i = 0; i < tags.length; i++) {
				if ((prop = tags[i].id) || (prop = tags[i].className)) {
					elem[prop.replace(classPrefix, '')] = tags[i];
				}
				tags[i][parentName] = elem;
			}
			if (this.init) elem.init.apply(elem, arguments);
			return elem;
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	fixFlash: function() {
		try {
		var objects = document.getElementsByTagName('object');
		for (var i = 0; i < objects.length; i++) {
			var isSet = false
			var object = objects[i];
			var params = object.getElementsByTagName('param');
			for (var j = 0; j < params.length; j++) {
				if (params[j].name.toLowerCase() == 'wmode') {
					isSet = true;
					break;
				}
			}
			if (!isSet) {
				var param = object.insertBefore(document.createElement('param'), objects[i].firstChild);
				param.name = 'wmode';
				param.value = 'opaque';
			}
			var embeds = object.getElementsByTagName('embed');
			if (embeds[0] && !embeds[0].getAttribute('wmode')) embeds[0].setAttribute('wmode', 'opaque');
			object.parentNode.replaceChild(object, object);
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	attachStyles: function() {
		try {
		var head;
		if ((head = document.getElementsByTagName("head")[0]) || (head = document.body)) {
			styleObject = head.appendChild(document.createElement("link"));
			styleObject.rel = "stylesheet";
			styleObject.type = "text/css";
			styleObject.href = "chrome://mystickies/content/MyStickies.css";
			styleObject.id = "ms_css";
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	richText: false,
	richTextSupported: function() {
		try {
		if (this.richText != undefined)
			return this.richText;
		var div = document.createElement('div');
		div.innerHTML = ('<iframe id="WYSIWYG_Editor_Testing_Browser_Features" style="display: none; visibility: hidden;"></iframe>');
		document.body.appendChild(div);
		test = typeof(document.getElementById('WYSIWYG_Editor_Testing_Browser_Features').contentWindow);
		document.body.removeChild(div);
		this.richText = (test == 'object');
		return this.richText;
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
};

///////////// Stack ////////////////////

MyStickies.Stack = {
	deleteStack: new Array(),
	noteStack: new Array(),

	updateDepths: function() {
		try {
		for(var i = 0; i < this.noteStack.length; i++) {
			this.noteStack[i].setDepth(MyStickies.startingZIndex + i);
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	add: function(note, newNote) {
		try {
		var depth = MyStickies.startingZIndex + this.noteStack.length;
		this.noteStack.push(note);
		note.setDepth(depth);
		document.body.appendChild(note);
		note.displayInit();
		if (newNote) note.editable.setfocused();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	remove: function(note) {
		try {
		document.body.removeChild(note);
		for(var i = 0; i < this.noteStack.length; i++) {
			if(this.noteStack[i] == note) this.noteStack.splice(i,1);
		}
		this.updateDepths();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	clearNotes : function() {
		try {
		for(var i = 0; i < this.noteStack.length; i++) {
			if(this.noteStack[i].parentNode) document.body.removeChild(this.noteStack[i]);
		}
		this.noteStack = new Array();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	moveToTop : function(note) {
		try {
		if (note == this.noteStack[this.noteStack.length - 1]) return;
		for(var i = 0; i < this.noteStack.length; i++) {
			if(this.noteStack[i] == note) {
				this.noteStack.splice(i, 1);
				this.noteStack.push(note);
				this.updateDepths();
				break;
			}
		}
		if (MyStickies.local) return;
		MyStickies.loader.save(MyStickies.url + 'note/update/depth?user='+MyStickies.username+'&pass='+MyStickies.password+'&z='+note.z+note.getSaveId());
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	saveNotes:function() {
		try {
		for(var i = 0; i < this.noteStack.length; i++) {
			if(this.noteStack[i].url && this.noteStack[i].url.length > 4)
				this.noteStack[i].save();
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	loadNotes:function() {
		try {
		if (!MyStickies.username.length || MyStickies.local) return;
		MyStickies.loader.load(MyStickies.loadUrl + 'note/loadUrl?user='+MyStickies.username+'&pass='+MyStickies.password+'&url=' + escape(location.href));
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	loadThese:function(notes) {
		try {
		for(var i = 0; i < notes.length; i++) {
			var note = new MyStickies.Note();
			note.loadNote(notes[i]);
			//eval("note.loadNote("+notes[i]+")");
			this.add(note);
		}
		this.noteStack.sort(
			function(a, b) {
				if (a.z > b.z) return 1;
				if (a.z < b.z) return -1;
				return 0;
			}
		);
		this.updateDepths();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
}

//////////////// Note //////////////////////

MyStickies.Note = MyStickies.utils.createDOMClass('\
<div style="position:absolute;" class="ms_Note">\
	<div class="ms_tagCont"></div>\
	<div class="ms_handle" title="Move Note">\
		<div class="ms_closer" title="Delete Note"></div>' +
//		<div class="ms_pin"></div>\
		'<div class="ms_tag"></div>\
		<span class="ms_optionButton"></span>\
		<span class="ms_username"></span></div>\
	<textarea class="ms_editable"></textarea>\
	<div class="ms_resizer" title="Resize Note"></div>' +
//	<div class="ms_email"></div>\
'</div>', 'note', 'ms_');

MyStickies.Note.prototype = {
	tmpId: null,
	changed: new Array(),

	init: function(tmpId) {
		try {
        /*this.iframe = document.createElement('iframe');
		this.iframe.src = "javascript:false";
		this.iframe.style.position = 'absolute';
		this.iframe.style.border = 'none';
		document.body.appendChild(this.iframe);
            */
		//this.iframe.style.background = '#cccccc';
		if (MyStickies.utils.richTextSupported()) {
			var div = document.createElement('div');
			div.className = 'ms_editable';
			div.style.position = 'relative';
			div.innerHTML = '<iframe frameborder="0" style="background:none"></iframe><div style="position:absolute;top:0px"></div>';
			this.replaceChild(div, this.editable);
			this.editable = div;
		}
		
		MyStickies.utils.extend(this.handle, MyStickies.Note.Handle);
		MyStickies.utils.extend(this.editable, MyStickies.Note.Editable);
		MyStickies.utils.extend(this.closer, MyStickies.Note.Closer);
		MyStickies.utils.extend(this.resizer, MyStickies.Note.Resizer);
		MyStickies.utils.extend(this.tag, MyStickies.Note.TagIcon);
		//MyStickies.utils.extend(this.email, MyStickies.Note.Email);
		
		this.setUrl(location.href);
		this.setTitle(document.title);
		var x = document.body.scrollLeft || window.pageXOffset || document.documentElement.scrollLeft;
		var y = document.body.scrollTop || window.pageYOffset || document.documentElement.scrollTop;
		x += MyStickies.defaultX;
		y += MyStickies.defaultY;
		this.move(x, y);
		this.setSize(MyStickies.defaultWidth, MyStickies.defaultHeight);
		this.setColor(MyStickies.defaultColor);
		this.content = '';
		this.tmpId = tmpId;
		
		/*this.pin.onclick = function(e) {
			e = MyStickies.Event.getEventObject(e);
			if (this.note.style.position == 'absolute') {
				this.style.background = 'url('+MyStickies.url+'images/unpin.png) no-repeat top right';
				this.note.style.position = 'fixed';
				this.note.style.top = parseInt(this.note.style.top) - (document.documentElement.scrollTop || document.body.scrollTop) + 'px';
			} else {
				this.style.background = '';
				this.note.style.position = 'absolute';
				this.note.move(this.note.x, parseInt(this.note.style.top) + (document.documentElement.scrollTop || document.body.scrollTop));
				this.note.save();
			}
		}*/
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	// this function gets called when note is added to document
	displayInit: function() {
		try {
		this.editable.init();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	// args = [0:id, 1:x, 2:y, 3:w, 4:h, 5:z, 6:text, 7:color, 8:user, 9:tags]
	loadNote: function(theArgs) {
		try {
		var args;
		if (arguments.length > 1) args = arguments;
		else args = theArgs;
		this.id = args[0] || null;
		this.setUrl(location.href);
		this.setTitle(document.title);
		this.move(args[1] || 100, args[2] || 100);
		this.setSize(args[3] || 100, args[4] || 100);
		this.setDepth(args[5] || MyStickies.startingZIndex);
		this.setText(args[6]);
		this.setColor(args[7] || MyStickies.defaultColor);
		this.setUser(args[8]);
		this.setTags(args[9] || new Array());
		
		this.changed = new Array();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	save: function() {
		try {
		if (!MyStickies.username.length) {
			if (!MyStickies.warnedAlready) {
				MyStickies.warnedAlready = true;
				//alert('Notes will not be saved because no account is currently seleted.');
				//TODO: something better than an alert
				return;
			}
		}
		if (MyStickies.local) return;
		if (!this.changed.length && this.id) return;
		
		var query = '';
		if(this.id || this.saved) {
			query = this.getSaveId();
			for (var i = 0; i < this.changed.length; i++) {
				query += "&" + this.changed[i] + '=' + escape(this[this.changed[i]]);
			}
		} else {
			var params = ["id","x","y","w","h","z","content","color","pageTitle","tmpId","url"];
			var val;
			for(var i = 0; i < params.length; i++) {
				if(val = this[params[i]])
					query += "&" + params[i] + "=" + escape(val);
			}
		}
		
		MyStickies.loader.save(MyStickies.url+'note/update/save?user='+MyStickies.username+'&pass='+MyStickies.password+query);
		this.saved = true;
		this.changed = new Array();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},


	getSaveId: function() {
		try {
		if (this.id) return '&id=' + this.id;
		return '&tmpId=' + this.tmpId + '&url=' + escape(this.url);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	deleteNote: function() {
		try {
		MyStickies.Stack.remove(this);
		if(this.id != null)
		MyStickies.Stack.deleteStack.push(this.id);
		if (MyStickies.local) return;
		MyStickies.loader.save(MyStickies.url+'note/update/delete?user='+MyStickies.username+'&pass='+MyStickies.password+this.getSaveId());
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	move: function(x, y) {
		try {
		this.x = x;
		this.y = y;
        this.style.left = x + 'px';
        this.style.top =  y + 'px';
		this.setChanged('x,y');
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	setSize: function(width, height) {
		try {
		this.w = Math.max(width, MyStickies.minWidth);
		this.h = Math.max(height, MyStickies.minHeight);
        this.style.width = this.w + 'px';
        this.style.height = this.h + 'px';
		this.editable.setSize(this.w - 4, this.h - 34);
		this.setChanged('w,h');
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	setColor: function(color) {
		try {
		if (color.charAt(0) != '#') color = '#' + color;
		this.color = color;
		this.style.backgroundColor = color;
		this.handle.style.backgroundColor = MyStickies.utils.changeShade(color, .72);
		this.handle.style.borderBottom = '1px solid ' + MyStickies.utils.changeShade(color, .44, true);
		this.setChanged('color');
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	setDepth: function(depth) {
		try {
		this.z = depth;
		this.style.zIndex = depth;
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	setText: function(text, fromEditable) {
		try {
		this.content = text;
		if (!fromEditable) this.editable.setText(text);
		this.setChanged('content');
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	setTitle: function(title) {
		try {
		this.pageTitle = title;
		this.setChanged('pageTitle');
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	setUrl: function(url) {
		try {
		this.url = url;
		this.setChanged('url');
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	setUser: function(user) {
		this.user = user;
		if (user != MyStickies.username)
			this.username.innerHTML = user;
	},

	setTags: function(tags) {
		try {
		if (typeof tags == 'string') tags = tags.split(';');
		for (var i = 0; i < tags.length; i++) {
			this.addTag(tags[i]);
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	addTag: function(tagText) {
		try {
		var newTag = new MyStickies.Note.Tag(this, tagText);
		this.tagCont.appendChild(newTag);
		if (!tagText) newTag.tagText.select();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	removeTag: function(tag) {
		try {
		this.tagCont.removeChild(tag);
		this.updateTags();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	updateTags: function() {
		if (MyStickies.local) return;
		var tags = [];
		var tagElements = this.tagCont.childNodes;
		for (var i = 0; i < tagElements.length; i++) {
			if (tagElements[i].tagText.value)
				tags.push(escape(tagElements[i].tagText.value));
		}
		tags = tags.join(',');
		MyStickies.loader.save(MyStickies.url+'note/update/tags?user='+MyStickies.username+'&pass='+MyStickies.password+this.getSaveId()+'&tags='+tags);
	},

	setfocused: function() {
		try {
		this.focused = true;
		this.tag.style.display = 'block';
		this.tagCont.style.display = 'block';
		//this.email.style.display = 'block';
		var note = this;
		note.editable.setfocused();
		MyStickies.Event.addListener(document, 'mousedown', function(){note.setblurred();});
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	setblurred: function() {
		try {
		this.focused = false;
		this.tag.style.display = 'none';
		this.tagCont.style.display = 'none';
		//this.email.style.display = 'none';
		var note = this;
		note.editable.setblurred();
		MyStickies.Event.removeListener(document, 'mousedown', function(){note.setblurred();});
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	onmousedown: function(e) {
		try {
		e = MyStickies.Event.getEventObject(e);
		MyStickies.Stack.moveToTop(this);
		// don't let clicks on this note blur it by hitting the document.onmousedown
		// or use setTimeout to keep from triggering document.onmousedown on this event
		var note = this;
		if (this.focused) e.stopPropagation();
		else setTimeout(function(){note.setfocused();}, 1);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	setChanged: function(props) {
		try {
		props = props.split(',');
		for (var i = 0; i < props.length; i++) {
			for (var j = 0; j < this.changed.length; j++) {
				if (this.changed[j] == props[i]) {
					var already = true;
					break;
				}
			}
			if (!already) this.changed.push(props[i]);
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
}


MyStickies.Note.Handle = {
	onmousedown: function(e) {
		try {
		e = MyStickies.Event.getEventObject(e);
		MyStickies.dontSelect = true;
		e.stopPropagation();
		MyStickies.Stack.moveToTop(this.note);
		var note = this.note;
		var handle = this;
		var diffX = e.pageX - note.x;
		var diffY = e.pageY - note.y;
		var noteX = note.x;
		var noteY = note.y;
		note.editable.setblurred();
		
		this.mousemove = function(e) {
			e = MyStickies.Event.getEventObject(e);
			if (Math.abs(e.pageX - diffX - noteX) + Math.abs(e.pageY - diffY - noteY) > 4)
				note.move(e.pageX - diffX, e.pageY - diffY);
		};
		this.mouseup = function(e) {
			e = MyStickies.Event.getEventObject(e);
			MyStickies.Event.removeListener(document, 'mousemove', handle.mousemove);
			MyStickies.Event.removeListener(document, 'mouseup', handle.mouseup);
			handle.mousemove = null;
			handle.mouseup = null;
			if (Math.abs(e.pageX - diffX - noteX) + Math.abs(e.pageY - diffY - noteY) > 4)
				note.save();
		};
		MyStickies.Event.addListener(document, 'mousemove', this.mousemove);
		MyStickies.Event.addListener(document, 'mouseup', this.mouseup);
		return false;
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	onclick: function(e) {
		e = MyStickies.Event.getEventObject(e);
		if (e.altKey) {
			// stop the alt action onkepup
			MyStickies.Event.addListener(document, 'keyup', MyStickies.stopAlt);
			var index = 0;
			var colors = MyStickies.colors;
			for (var i = 0; i < colors.length; i++) {
				if (this.note.color == colors[i]) {
					index = i < (colors.length - 1) ? i + 1 : 0;
					break;
				}
			}
			MyStickies.defaultColor = colors[index];
			this.note.setColor(colors[index]);
			this.checkAndSave();
		}
	},
	
	checkAndSave: function() {
		try {
		var note = this.note;
		// give it some time so we don't save on every click
		if (this.timeout) clearTimeout(this.timeout);
		this.timeout = setTimeout(function() {
			note.handle.timeout = null;
			note.save();
		}, 500);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
}

MyStickies.Note.Editable = {
	init: function() {
		try {
		if (MyStickies.utils.richTextSupported()) {
			this.frame = this.firstChild;
			this.setupFrame();
			var editable = this;
			this.frame.contentWindow.document.onkeyup = 
			this.frame.contentWindow.document.onmouseup = function() {
				editable.checkAndSave();
			}
			this.frame.contentWindow.document.onmousedown = function() {
				editable.note.onmousedown();
			}
			this.onkeyup = this.onmouseup = null;
			this.cover = this.lastChild;
			this.removeChild(this.cover);
		} else {
			MyStickies.Event.addListener(this, 'keyup', this, this.checkAndSave);
			MyStickies.Event.addListener(this, 'mouseup', this, this.checkAndSave);
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	setText: function(text) {
		try {
		if (this.frame && this.frame.contentWindow.document.body) {
			this.frame.contentWindow.document.body.innerHTML = text || '';
		} else {
			this.value = text;
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	getText: function() {
		try {
		if (this.frame)
			return this.frame.contentWindow.document.body.innerHTML;
		else
			return this.value;
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	setSize: function(w, h) {
		try {
		this.style.width = w + 'px';
		this.style.height = h + 'px';
		if (this.cover) {
			this.cover.style.width = w + 'px';
			this.cover.style.height = h + 'px';
		}
		if (this.frame) {
			this.frame.style.width = w + 'px';
			this.frame.style.height = h + 'px';
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	setfocused: function() {
		try {
		if (this.frame) {
			this.frame.contentWindow.focus();
		} else {
			this.focus();
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	setblurred: function() {
		if (this.frame) {
			this.appendChild(this.cover);
			var frame = this.frame;
			this.cover.onclick = function() {
				this.parentNode.removeChild(this);
				frame.contentWindow.focus();
			}
		}
	},
	
	setupFrame: function(contents) {
		try {
		if (!this.frame)
			return;
		var doc = this.frame.contentWindow.document;
		doc.designMode = 'On';
		doc.open();
		doc.write('<html><head><link rel="stylesheet" type="text/css" href="chrome://mystickies/content/Frame.css" /></head><body></body></html>');
		doc.close();
		this.setText(contents);
		this.frame.contentWindow.MyStickies = MyStickies;
		MyStickies.Event.addListener(doc, 'keydown', doc, MyStickies.Note.Editable.RichText.keydown);
		MyStickies.Event.addListener(doc, 'keypress', doc, MyStickies.Note.Editable.RichText.keystop);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	checkAndSave: function() {
		try {
		var note = this.note;
		// if not changed, don't save
		if (note.content == this.getText()) return;
		note.setText(this.getText(), true);
		// give it some time so we don't save on every keystroke
		if (this.timeout) clearTimeout(this.timeout);
		this.timeout = setTimeout(function() {
			note.editable.timeout = null;
			note.save();
		}, 500);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
}

MyStickies.Note.Editable.RichText = {
	keydown: function(e) {
		e = MyStickies.Event.getEventObject(e);
		if (e.ctrlKey && e.which != e.KEY_CTRL) {
			switch (e.toChar(e.which)) {
				case 'B':
					if (this.queryCommandEnabled('bold')) this.execCommand('bold', false, '');
					break;
				case 'I':
					if (this.queryCommandEnabled('bold')) this.execCommand('italic', false, '');
					break;
				case 'U':
					if (this.queryCommandEnabled('bold')) this.execCommand('underline', false, '');
					break;
				case 'L':
					if (this.queryCommandEnabled('CreateLink')) this.execCommand('CreateLink', false, prompt('Enter a URL:', 'http://'));
					break;
				default:
					return;
			}
			this.keystop = true;
			e.stop();
			return false;
		}
	},
	
	keystop: function(e) {
		if (this.keystop) {
			e.stop();
			this.keystop = false;
		}
	}
}

MyStickies.Note.Resizer = {
	onmousedown: function(e) {
		try {
		e = MyStickies.Event.getEventObject(e);
		e.stopPropagation();
		MyStickies.dontSelect = true;
		MyStickies.Stack.moveToTop(this.note);
		var note = this.note;
		var resizer = this;
		var editable = this.note.editable;
		var diffW = e.pageX - parseInt(note.style.width);
		var diffH = e.pageY - parseInt(note.style.height);
		note.editable.setblurred();
		
		this.mousemove = function(e) {
			note.setSize(e.pageX - diffW, e.pageY - diffH);
		};
		this.mouseup = function(e) {
			note.setSize(e.pageX - diffW, e.pageY - diffH);
			MyStickies.Event.removeListener(document, 'mousemove', resizer.mousemove);
			MyStickies.Event.removeListener(document, 'mouseup', resizer.mouseup);
			resizer.mousemove = null;
			resizer.mouseup = null;
			note.save();
		};
		MyStickies.Event.addListener(document, 'mousemove', this.mousemove);
		MyStickies.Event.addListener(document, 'mouseup', this.mouseup);
		return false;
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
}

MyStickies.Note.Closer = {
	onclick: function() {
		try {
		this.note.deleteNote();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
}

MyStickies.Note.TagIcon = {
	onclick: function() {
		try {
		this.note.addTag();
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
}

MyStickies.Note.Email = {
	onclick: function() {
		try {
		if (MyStickies.local) return;
		MyStickies.loader.save(MyStickies.url+'note/update/email?user='+MyStickies.username+'&pass='+MyStickies.password+this.note.getSaveId());
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
}

MyStickies.Note.Tag = MyStickies.utils.createDOMClass('\
<div class="ms_newTag">\
	<input type="text" class="ms_tagText" />\
</div>', 'tag', 'ms_');

MyStickies.Note.Tag.prototype = {
	init: function(note, content) {
		try {
		this.note = note;
		this.text = content || '';
		var tag = this;
		this.tagText.value = this.text;

		this.tagText.onmouseup = function() {
			this.select();
		}
		this.tagText.onkeydown = function(e) {
			e = MyStickies.Event.getEventObject(e);
			if (e.which == 13) note.addTag();
			if (e.which == 27) note.removeTag(tag);
		}
		
		this.tagText.onkeyup = function() {
			tag.checkAndSave();
		},
	
		this.tagText.onmouseup = function() {
			tag.checkAndSave();
		},
		
		this.tagText.onblur = function() {
			if (!this.value) {
				note.removeTag(tag);
			}
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},
	
	checkAndSave: function() {
		try {
		if (this.timeout) clearTimeout(this.timeout);
		// if not changed, don't save
		if (this.text == this.tagText.value) return;
		// give it some time so we don't save on every keystroke
		var tag = this;
		var note = this.note;
		this.timeout = setTimeout(function() {
			tag.timeout = null;
			note.updateTags();
			tag.text = tag.tagText.value;
		}, 500);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	},

	ondblclick: function() {
		try {
		this.note.removeTag(this);
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}

};

MyStickies.Message = MyStickies.utils.createDOMClass('\
<div style="position:fixed;top:0;right:0;background:#c00;color:white;display:inline;padding:0 4px"></div>');

MyStickies.utils.extend(MyStickies.Message, {
	messages: [],
	messageObj: null,
	
	add: function(msg) {
		
	},
	
	remove: function(msg) {
		
	}
});

MyStickies.Message.prototype = {
	
	init: function(msg) {
		this.innerHTML = msg;
	}
}

if (!MyStickies.loader) {
	MyStickies.loader = {
		load: function(url) {
			try {
			var script = document.createElement('script');
			script.src = url;
			document.body.appendChild(script);
			} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
		},
		
		save: function(url) {
			try {
			var img = new Image();
			img.src = url;
			} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
		}
	}
}

MyStickies.Help = MyStickies.utils.createDOMClass('\
<div style="position:absolute;z-index:1000;white-space:nowrap;border:1px solid #999;padding:10px;left:100px;top:100px;background:#fff;width:400px">\
	<h2>MyStickies: Getting Started</h2>\
	<p>[Flash piece with video]</p>\
	<p><a href="#" style="float:right" class="ms_closeLink">[Close]</a>\
	<label for="again">\
	<input name="again" type="checkbox" id="again" value="true" />\
	Do not show again</label></p>\
</div>', 'help', 'ms_');

MyStickies.Help.prototype = {
	init: function() {
		try {
		var prefs = MyStickies.Prefs;
		var help = this;
		this.closeLink.onclick = function() {
			try {
				if (help.again.checked) prefs.setOption('viewHelp', false);
				help.parentNode.removeChild(help);
			} catch (e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
			return false;
		}
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
};


MyStickies.Event = {
	addListener: function(element, event, object, listener, stopEvent) {
		// if object is not passed, place null in it's place
		if (typeof object != 'object') {
			stopEvent = listener;
			listener = object;
			object = null;
		}
		// don't let it get added twice by mistake
		this.removeListener(element, event, object, listener, stopEvent);
		var proxy = function(e) {
			e = MyStickies.Event.getEventObject(e);
			if (typeof listener == 'string') 
				listener = object ? object[listener] : eval(listener);
			if (object) listener.call(object, e);
			else listener(e);
			if (stopEvent) e.stop();
		}
		if (!this.listeners) this.listeners = new Array();
		this.listeners.push([element, event, object, listener, stopEvent, proxy]);
		if (element.addEventListener)
			element.addEventListener(event, proxy, false);
		else if (element.attachEvent) {
			element.attachEvent('on' + event, proxy);
		}
	},
	
	removeListener: function(element, event, object, listener, stopEvent) {
		// if object is not passed, place null in it's place
		if (typeof object != 'object') {
			stopEvent = listener;
			listener = object;
			object = null;
		}
		if (!this.listeners) return;
		for (var i = 0; i < this.listeners.length; i++) {
			var ev = this.listeners[i];
			if (element == ev[0] &&
				event == ev[1] &&
				object == ev[2] &&
				listener == ev[3] &&
				stopEvent == ev[4]) {
				this.listeners.splice(i, 1);
				if (element.removeEventListener)
					element.removeEventListener(event, ev[5], false);
				else if (element.detachEvent)
					element.detachEvent('on' + event, ev[5]);
				break;
			}
		}
	},
	
	addEvent: function(element, event, object, listener, stopEvent) {
		// if object is not passed, place null in it's place
		if (typeof object != 'object') {
			stopEvent = listener;
			listener = object;
			object = null;
		}
		// don't let it get added twice by mistake
		this.removeEvent(element, event, object, listener, stopEvent);
		var wrapperName = event + '$wrapper';
		var wrapFuncName = event + '$wrapFunc';
		var wrapper = element[wrapperName];
		if (!wrapper) {
			element[wrapFuncName] = element[event];
			wrapper = element[wrapperName] = {listeners: []};
			element[event] = function() {
				var retval = element[wrapFuncName].apply(element, arguments);
				for (var i = 0; i < wrapper.listeners.length; i++) {
					var object = wrapper.listeners[i].object;
					var listener = wrapper.listeners[i].listener;
					var stopEvent = wrapper.listeners[i].stopEvent;
					if (typeof listener == 'string')
						listener = object ? object[listener] : eval(listener);
					listener.apply(object, arguments);
					if (stopEvent) break;
				}
				return retval;
			}
		}
		wrapper.listeners.push({object: object, listener: listener, stopEvent: stopEvent});
		return wrapper;
	},
	
	removeEvent: function(element, event, object, listener, stopEvent) {
		// if object is not passed, place null in it's place
		if (typeof object != 'object') {
			stopEvent = listener;
			listener = object;
			object = null;
		}
		var wrapperName = event + '$wrapper';
		var wrapFuncName = event + '$wrapFunc';
		var wrapper = element[wrapperName];
		if (!wrapper) return;
		for (var i = 0; i < wrapper.listeners.length; i++) {
			var _listener = wrapper.listeners[i].listener;
			var _object = wrapper.listeners[i].object;
			var _stopEvent = wrapper.listeners[i].stopEvent;
			if (object == _object && listener == _listener && stopEvent == _stopEvent) {
				element[event] = element[wrapFuncName];
				element[wrapFuncName] = null;
				return wrapper.listeners.splice(i, 1)[0];
			}
		}
	},
	
	unloadCache: function() {
		if (!this.listeners) return;
		for (var i = 0; i < this.listeners.length; i++) {
			var element = this.listeners[i][0];
			var event = this.listeners[i][1];
			var proxy = this.listeners[i][5];
			if (element.removeEventListener)
				element.removeEventListener(event, proxy, false);
			else if (element.detachEvent)
				element.detachEvent('on' + event, proxy);
			this.listeners[i] = null;
		}
		this.listeners = null;
	},
	
	getEventObject: function(e) {
		try {
		if (!e) e = window.event;
		if (!e.stopPropagation) e.stopPropagation = function() { e.cancelBubble = true; };
		if (!e.preventDefault) e.preventDefault = function() { e.returnValue = false; };
		if (e.target) while (e.target.nodeType == 3) e.target = e.target.parentNode;
		if (!e.target && e.srcElement) e.target = e.srcElement;
		if (!e.relatedTarget && (e.fromElement || e.toElement)) e.relatedTarget = e.fromElement ? e.fromElement : e.toElement;
		if (!e.pageX && e.clientX) e.pageX = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
		if (!e.pageY && e.clientY) e.pageY = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
		if (!e.layerX && e.offsetX) e.layerX = e.offsetX;
		if (!e.layerY && e.offsetY) e.layerY = e.offsetY;
		e.callListener = function(listener, currentTarget) {
			e.currentTarget = currentTarget;
			return listener.call(currentTarget, e);
		}
		e.stop = function() {
			e.stopPropagation();
			e.preventDefault();
		}
		var keys = {
			KEY_BACKSPACE: 8,
			KEY_TAB: 9,
			KEY_ENTER: 13,
			KEY_SHIFT: 16,
			KEY_CTRL: 17,
			KEY_ALT: 18,
			KEY_PAUSE: 19,
			KEY_CAPS_LOCK: 20,
			KEY_ESCAPE: 27,
			KEY_PAGE_UP: 33,
			KEY_PAGE_DOWN: 34,
			KEY_END: 35,
			KEY_HOME: 36,
			KEY_LEFT_ARROW: 37,
			KEY_UP_ARROW: 38,
			KEY_RIGHT_ARROW: 39,
			KEY_DOWN_ARROW: 40,
			KEY_INSERT: 45,
			KEY_DELETE: 46,
			KEY_LEFT_WINDOW: 91,
			KEY_RIGHT_WINDOW: 92,
			KEY_SELECT: 93,
			KEY_F1: 112,
			KEY_F2: 113,
			KEY_F3: 114,
			KEY_F4: 115,
			KEY_F5: 116,
			KEY_F6: 117,
			KEY_F7: 118,
			KEY_F8: 119,
			KEY_F9: 120,
			KEY_F10: 121,
			KEY_F11: 122,
			KEY_F12: 123,
			KEY_NUM_LOCK: 144,
			KEY_SCROLL_LOCK: 145
		};
		for (var key in keys) {
			if (key.indexOf('KEY') == 0)
				e[key] = keys[key];
		}
		// returns the keyboard code from the char or the char from the code
		// NOTE: char is always uppercase when getting char form code
		e.toCode = function(character) {
			return character.toUpperCase().charCodeAt(0);
		}
		e.toChar = function(code) {
			return String.fromCharCode(code);
		}
		return e;
		} catch(e) {/*alert(e.fileName  + ':' + e.lineNumber + ' -- ' + e.message);*/}
	}
};

MyStickies.Event.addListener(window, 'unload', MyStickies.Event, 'unloadCache');

if (!MyStickies.loaded) MyStickies.load();
