function openWord( op, id )
{
	var x = ilikeVisualGetX( op );
	var y = ilikeVisualGetY( op );
	var o = document.getElementById( 'word' + id );
	o.style.top = y + 'px';
	o.style.left = ( x ) + 'px';
	o.style.display = 'block';
	return false;
}
function hideWord( id )
{
	var o = document.getElementById( 'word' + id );
	o.style.display = 'none';
	return false;
}



String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,'') }
String.prototype.unescHtml = function(){ var i,e={'&lt;':'<','&gt;':'>','&amp;':'&','&quot;':'"'},t=this; for(i in e) t=t.replace(new RegExp(i,'g'),e[i]); return t }

function loadTags(t) { tags = t }

Fold = {
	folded : {},
	go : function(){
		if(!document.getElementsByTagName || !document.childNodes) return
		var fold,label,newfold,newlabel,i
		fold = Cookies.get('_fold')
		if(fold) { fold = fold.split(' '); for(i in fold) { this.folded[fold[i]] = 1 } }
		var folds = $c('fold',document,'li')
		this.ffhack() //weird spacing bug in ff
		for(fold in folds) { fold = folds[fold]
			label = $c('label',fold)[0]
			if(label) {
				label.label = $tag('span',label).innerHTML.replace(/[ ;]+/g,'')
				this.makeArrow(label,'d');

				newfold = document.createElement('li')
				newfold.className = fold.className; swapClass(newfold,'fold','grey')

				newlabel = label.cloneNode(true)
				$tag('img',newlabel).src="/static/img/arrow.r.gif"

				newfold.appendChild(newlabel)
				fold.parentNode.insertBefore(newfold,fold)

				if(this.folded[label.label]) { newfold.style.display = 'block'; fold.style.display = 'none' }
				else newfold.style.display = 'none'

				label.style.cursor = newlabel.style.cursor = 'pointer'
				label.onclick = this.makeToggle(newfold, fold, label.label, true)
				newlabel.onclick = this.makeToggle(fold, newfold, label.label)
	}}},
	makeArrow : function(label,i){
		var img = document.createElement('img')
		img.src = "/static/img/arrow."+i+".gif"; img.width = img.height = 8;
		if(i == 'r') img.className = 'grey'
		addClass(label,'arrow')
		label.insertBefore(img, label.firstChild)
	},
	makeToggle : function(show,hide,cookieKey,cookieSet){ return (function(){
		var cookie='',f
		show.style.display = 'block'; hide.style.display = 'none'
		if(cookieSet) Fold.folded[cookieKey] = 1
		else delete Fold.folded[cookieKey]
		for(f in Fold.folded) cookie += f + ' '; Cookies.set('_fold', cookie, 30)
	})},
	ffhack : function() { var u=$c('bundles',document,'ul'),i
		for(i in u) {i=u[i]; var b=document.createElement('li'); b.innerHTML='&nbsp;'; b.className='bundle ffhack'; i.insertBefore(b,i.firstChild) }
}}

Cookies = {
	set : function(name,value,days){ var expires = '', days = days||30
		var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); expires = "; expires="+date.toGMTString()
		document.cookie = name+"="+value+expires+"; path=/"
	},
	get : function(name){
		var ca = document.cookie.split(';'),i,c; name += '='
		for(i=0; i < ca.length; i++) {
			c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length)
			if (c.indexOf(name) == 0) return c.substring(name.length,c.length)
		}
		return null
}}

Mp3 = {
	playimg: null,
	player: null,
	go: function() {
		var all = $c('mp3', document, 'a')
		for (var i = 0, a; a = all[i]; i++) {
			var img = document.createElement('img')
			img.src = '/static/img/mp3/play.gif'; img.title = 'listen'
			img.className = 'player'
			img.height = img.width = 12
			img.onclick = Mp3.makeToggle(img, a.href)
			a.parentNode.insertBefore(img, a)
	}},
	toggle: function(img, url) {
		if (Mp3.playimg == img) Mp3.destroy()
		else {
			if (Mp3.playimg) Mp3.destroy()
			img.src = '/static/img/mp3/stop.gif'; Mp3.playimg = img;
			Mp3.player = document.createElement('span')
			Mp3.player.innerHTML = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"' +
			'codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"' +
			'width="50" height="15" align="middle" class="player">' +
			'<param name="allowScriptAccess" value="sameDomain" />' +
			'<param name="flashVars" value="theLink='+url+'" />' +
			'<param name="movie" value="/static/swf/mp3.swf" /><param name="quality" value="high" />' +
			'<param name="bgcolor" value="#ffffff" />' +
			'<embed src="/static/swf/mp3.swf" flashVars="theLink='+url+'"'+
			'quality="high" bgcolor="#ffffff" width="50" height="15" name="player"' +
			'align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"' +
			' pluginspage="http://www.macromedia.com/go/getflashplayer" class="player" /></object>'
			img.parentNode.insertBefore(Mp3.player, img.nextSibling)
	}},
	destroy: function() {
		Mp3.playimg.src = '/static/img/mp3/play.gif'; Mp3.playimg = null
		Mp3.player.removeChild(Mp3.player.firstChild); Mp3.player.parentNode.removeChild(Mp3.player); Mp3.player = null
	},
	makeToggle: function(img, url) { return function(){ Mp3.toggle(img, url) }}
}

Crumb = {
	go: function(root){
		var p = $id('crumb'), o = document.createElement('input')
		var tag = p.innerHTML.unescHtml()
		o.className = 'crumb'
		o.originalValue = o.value = tag
		o.root = root || '/tag/'
		o.onblur = Crumb.blur; o.onfocus = Crumb.focus
		o.onmouseover = Crumb.mouseover; o.onmouseout = Crumb.mouseout
		o.onkeyup = o.onkeypress = Crumb.keyhandler
		p.innerHTML = ''; p.appendChild(o)
		resizeToText(o, tag, 40)
	},
	mouseover: function() { addClass(this, 'crumb-focus') },
	mouseout: function() { if(!this.focused) rmClass(this, 'crumb-focus') },
	focus: function() { this.focused = true; addClass(this, 'crumb-focus') },
	blur: function() {
		if (this.submitting) return false
		this.focused = false
		this.value = this.originalValue
		rmClass(this, 'crumb-focus')
		resizeToText(this, this.value, 40)
	},
	keyhandler: function(e) { e = e||window.event
		if (e.type == 'keypress' && e.keyCode == 13) {
			var tag = this.value.replace(/ +/g, '+')
			if (tag) {
				this.submitting = true
				location.href = this.root + tag
		}}
		resizeToText(this, this.value, 40)
}}

function footer() {
	var h = windowHeight(), footer = $id('footer'), bottom = getY($id('bottom')), sidebar = $id('sidebar')
	var fh = footer.clientHeight || footer.offsetHeight // todo: why does IE report 0 for clientHeight?
	if (bottom != 0) {
		if (bottom < h - fh) footer.style.marginTop = ((h - fh)-bottom-3)+'px'
		else footer.style.marginTop = 0
	}
	footer.parentNode.style.visibility = 'visible'
}

function addEngine()
{
	if ((typeof window.sidebar == "object") &&
		(typeof window.sidebar.addSearchEngine == "function")) {
			window.sidebar.addSearchEngine(
				"http://del.icio.us/search/delicious.src",
				"http://del.icio.us/static/img/search/delicious.gif",
				"delicious",
				'Web' );
	}
}


// get previous/next non-text node
function previousElement(o) {
	if(o.previousSibling) { while (o.previousSibling.nodeType != 1) o = o.previousSibling; return o.previousSibling }
	else return false
}
function nextElement(o) {
	if(o.nextSibling) { while (o.nextSibling.nodeType != 1) o = o.nextSibling; return o.nextSibling }
	else return false
}

// styling functions
function isA(o,klass){ if(!o.className) return false; return new RegExp('\\b'+klass+'\\b').test(o.className) }
function addClass(o,klass){ if(!isA(o,klass)) o.className += ' ' + klass }
function rmClass(o,klass){ o.className = o.className.replace(new RegExp('\\s*\\b'+klass+'\\b'),'') }
function swapClass(o,klass,klass2){ var swap = isA(o,klass) ? [klass,klass2] : [klass2,klass]; rmClass(o,swap[0]); addClass(o,swap[1]) }
function getStyle(o,s) {
	if (document.defaultView && document.defaultView.getComputedStyle) return document.defaultView.getComputedStyle(o,null).getPropertyValue(s)
	else if (o.currentStyle) { return o.currentStyle[s.replace(/-([^-])/g, function(a,b){return b.toUpperCase()})] }
}
// shorter names for grabbing stuff
function $id(id){ return document.getElementById(id) }
function $tags(t,o){ o=o||document; return o.getElementsByTagName(t) }
function $tag(t,o,i) { o=o||document; return o.getElementsByTagName(t)[i||0] }
// get elements by class name, eg $c('post', document, 'li')
function $c(c,o,t) { o=o||document;
	if (!o.length) o = [o]
	else if(o.length == 1 && !o[0]) o = [o] // opera, you're weird
	var elements = []
	for(var i = 0, e; e = o[i]; i++) {
		if(e.getElementsByTagName) {
			var children = e.getElementsByTagName(t || '*')
			for (var j = 0, child; child = children[j]; j++) if(isA(child,c)) elements.push(child)
	}}
	return elements
}

function extend(dest, src) {
	for (var p in src) dest[p] = src[p]
	return dest
}

// get mouse pointer position
function pointerX(e) { return e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)) }
function pointerY(e) { return e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) }

// get window size
function windowHeight() { return self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0 }
function windowWidth() { return self.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0 }

// get pixel position of an object
function getY(o){ var y = 0
	if (o.offsetParent) while (o.offsetParent) { y += o.offsetTop; o = o.offsetParent }
	return y
}
function getX(o){ var x = 0
	if (o.offsetParent) while (o.offsetParent) { x += o.offsetLeft; o = o.offsetParent }
	return x
}

// form stuff
function getRadioValue(o) {
	for(var i = 0, r; r = o[i]; i++) if (r.checked && r.value) return r.value
	return false
}

// todo: make less crap
function resizeToText(o, text, margin) {
	margin = margin || 0
	var c = $id(o.id + '-copy')
	if (!c) { makeResizeThing(o); c = $id(o.id + '-copy') }
	var esc = {'<':'[','>':']',' ':'&nbsp;'}
	for(var i in esc) text=text.replace(new RegExp(i,'g'), esc[i])
	c.innerHTML = text
	o.style.width = c.offsetWidth + margin + 'px'
}
function makeResizeThing(src) {
	var o = document.createElement('div')
	o.style.position = 'absolute'; o.style.top = o.style.left = 0
	o.style.visibility = 'hidden'
	o.style.fontSize = getStyle(src, 'font-size')
	o.style.fontFamily = getStyle(src, 'font-family')
	o.id = src.id + '-copy'
	src.parentNode.appendChild(o)
}

// event functions
function falseFunc(){ return false }
function addLoadEvent(f) { var old = window.onload
	if (typeof old != 'function') window.onload = f
	else { window.onload = function() { old(); f() }}
}

function mailer(oName,oDomain) {
 email="mailto:" + oName + "@" + oDomain;
 window.location=email;
}

//addLoadEvent(rmPostAddEvent)

// the following two functions ganked from prototype (see http://prototype.conio.net)
// (c) 2005 Sam Stephenson
var Class = {
	create: function() {
		return function() { this.initialize.apply(this, arguments) }
}}
Function.prototype.bind = function(o) {
	var __method = this
	return function() { return __method.apply(o, arguments) }
}












function init() {
 var elements = ['alpha','freq','rec','pop','copy','network'], divs={}, freqSort=[], freqMap={}, t,i
	for(i in elements) divs[elements[i]] = makeDiv(elements[i] + 'tags')
	elements = elements.concat('suggest','tags','yourtags','alphasort','freqsort')
	for(i in elements) h[elements[i]] = $id(elements[i])
	for(t in tags) {
		if (!freqMap[tags[t]]) { freqMap[tags[t]] = {}; freqSort[freqSort.length] = tags[t] }
		freqMap[tags[t]][t] = true;
		sections[0][t.toLowerCase()] = makeTag(divs.alpha, t, 'swap')
	}
	freqSort.sort(function(a,b){return b-a})
	for(i in freqSort) {
		for(t in freqMap[freqSort[i]]) {
			tagSearch += t + ' '
			sections[1][t.toLowerCase()] = makeTag(divs.freq, t, 'swap')
	}}
	for(t in copytags) { t = copytags[t]
		sections[4][t.toLowerCase()] = makeTag(divs.copy, t, 'swap')
		if(!sections[0][t]) tagSearch += t + ' '
	}
	if(copytags.length > 0) {
		$tag('span',h.copy).innerHTML = copyuser + "'s tags"
		h.copy.style.display = 'block'; h.copy.appendChild(divs.copy)
	}
	for(t in tagFor) { t = 'for:'+tagFor[t]
		sections[5][t.toLowerCase()] = makeTag(divs.network, t, 'swap')
		tagSearch += t + ' '
	}
	if(tagFor.length > 0) { h.network.style.display = 'block'; h.network.appendChild(divs.network) }
	for(t in tagPop) { t = tagPop[t]
		sections[2][t.toLowerCase()] = makeTag(divs.pop, t, 'swap')
		if(!sections[0][t.toLowerCase()] && !sections[4][t.toLowerCase()]) tagSearch += t + ' '
	}
	if(tagPop.length > 0) { h.pop.style.display = 'block'; h.pop.appendChild(divs.pop) }
	for(t in tagRec) { t = tagRec[t]
		sections[3][t.toLowerCase()] = makeTag(divs.rec, t, 'swap')
		for(i in sections) {
			if(sections[i][t.toLowerCase()]) { addClass(sections[i][t.toLowerCase()], 'recommended') }
	}}
	if(tagRec.length > 0) { h.rec.style.display = 'block'; h.rec.appendChild(divs.rec) }
	if(freqSort.length > 0) {
		h.yourtags.style.display = 'block'; h.freq.style.display = 'none'
		h.alpha.appendChild(divs.alpha); h.freq.appendChild(divs.freq)
	}
	document.onkeydown = document.onkeypress = document.onkeyup = handler
	updateHilight()
	if(window.Fold) Fold.go()
}

function makeDiv(id) { var obj=document.createElement('div'); obj.id=id; return obj }

function makeTag(parent, tag, js) {
	parent.appendChild(document.createTextNode(' '))
	var obj = document.createElement('a')
	obj.className = 'tag'
	obj.setAttribute('href','javascript:'+js+'("'+tag.replace(/"/g,'\\"')+'")')
	obj.appendChild(document.createTextNode(tag))
	if(tags[tag] < 2) obj.style.color = '#66f'
	if(tags[tag] == 2) obj.style.color = '#44f'
	parent.appendChild(obj)
	return obj
}

function select(t) { var i; t=t.toLowerCase()
	selected[t] = true; for(i in sections) if(sections[i][t]) addClass(sections[i][t], 'selected')
}
function deselect(t) { var i; t=t.toLowerCase()
	delete selected[t]; for(i in sections) if(sections[i][t]) rmClass(sections[i][t], 'selected')
}

function swap(tag){
	var tagArray = h.tags.value.trim().split(' '), present=false, t, tl=tag.toLowerCase()
	if (tagArray[0].trim() == '') tagArray.splice(0,1);
	for (t=0; t<tagArray.length; t++) {
		if (tagArray[t].toLowerCase() == tl) { tagArray.splice(t,1); deselect(tag); present=true; t-=1  }
	}
	if (!present) { tagArray.push(tag); select(tag) }
	var content = tagArray.join(' ')
	lastEdit = h.tags.value = (content.length > 1) ? content + ' ' : content
	hideSuggestions()
	focusTo(h.tags)
}

function complete(tag) { var tagArray=h.tags.value.split(' ')
	if(typeof tag == 'undefined') tag = suggestions[suggestions.picked].innerHTML.unescHtml() // tab complete rather than click complete
	tagArray[currentTag.index] = tag
	var text = tagArray.join(' ')
	h.tags.value = (text.substr(-1,1) == ' ' ? text : text + ' ' )
	hideSuggestions()
	updateHilight()
	focusTo(h.tags)
	$id("tags").blur();   //hack to "wake up" safari
	$id("tags").focus();
}

// focus the caret to end of a form input (+ optionally select some text)
var range=0 //ie
function focusTo(obj, selectFrom) {
	if (typeof selectFrom == 'undefined') selectFrom = obj.value.length
	if(obj.createTextRange){ //ie + opera
		if (range == 0) range = obj.createTextRange()
		range.moveEnd("character",obj.value.length)
		range.moveStart("character",selectFrom)
		//obj.select()
		//range.select()
		setTimeout('range.select()', 10)
	} else if (obj.setSelectionRange){ //ff
		obj.select()
		obj.setSelectionRange(selectFrom,obj.value.length)
	} else { //safari :(
	 obj.blur()
}}

function sort(text) { var lists=['alpha','freq'], l
	for(l in lists) { l = lists[l]
		h[l].style.display = (l == text) ? 'inline' : 'none'
		h[l + 'sort'].className = (l == text) ? 'noclicky' : 'clicky'
}}

function updateHilight() { var tagArray=h.tags.value.toLowerCase().split(' '), tagHash={}
	if (tagArray[0].trim() == '') tagArray.splice(0,1);
	for (t in tagArray) {
		if(tagArray[t] != '') {
			select(tagArray[t])
			tagHash[tagArray[t]] = true
	}}
	for (t in selected) {if (!tagHash[t]) deselect(t)}
	return [tagArray, tagHash]
}

function hideSuggestions() { h.suggest.parentNode.parentNode.style.visibility='hidden' }
function showSuggestions() { suggest(0); h.suggest.parentNode.parentNode.style.visibility='visible' }

function updateSuggestions() {
	if(!getCurrentTag() || !currentTag.text) { hideSuggestions(); return false }

	while (h.suggest.hasChildNodes()) h.suggest.removeChild(h.suggest.firstChild)
	delete suggestions; suggestions = new Suggestions();
	var tagArray = h.tags.value.toLowerCase().split(' '), txt=currentTag.text.escRegExp(), tagHash={}, t
	for(t in tagArray) tagHash[tagArray[t]] = true

	var search = tagSearch.match(new RegExp(("(?:^| )("+txt+"[^ ]+)"), "gi"))
	if(search){
		for (i=0; i<search.length && suggestions.length<10; i++) {
			tl = search[i].trim()
			if(tagHash[tl])  continue // do not suggest already typed tag
			suggestions[suggestions.length] = makeTag(h.suggest, tl, 'complete')
			suggestions.length++
	}}
	if (suggestions.length > 0) showSuggestions()
	else hideSuggestions()
}

function suggest(index) {
	if(suggestions.length == 1) index = 0
	if(suggestions[suggestions.picked]) suggestions[suggestions.picked].className = 'tag'
	suggestions[suggestions.picked = index].className = 'tag selected'
}

function getCurrentTag() {
	if(h.tags.value == lastEdit) return true // no edit
	if(h.tags == '') return false
	currentTag = {}
	var tagArray=h.tags.value.toLowerCase().split(' '), oldArray=lastEdit.toLowerCase().split(' '), currentTags = [], matched=false, t,o
	for (t in tagArray) {
		for (o in oldArray) {
			if(typeof oldArray[o] == 'undefined') { oldArray.splice(o,1); break }
			if(tagArray[t] == oldArray[o]) { matched = true; oldArray.splice(o,1); break; }
		}
		if(!matched) currentTags[currentTags.length] = t
		matched=false
	}
	// more than one word changed... abort
	if(currentTags.length > 1) { hideSuggestions(); return false }
	currentTag = { text:tagArray[currentTags[0]], index:currentTags[0] }
	return true
}

function handler(event) { var e=(event||window.event) //w3||ie
	if (e.type == 'keydown') {
		if(suggestions.length > 0) {
			switch(e.keyCode) {
				case 38: suggest((suggestions.picked + 1) % suggestions.length); break
				case 40: suggest(suggestions.picked == 0 ? suggestions.length - 1 : suggestions.picked - 1); break
				
	}}} else if (e.type == 'keypress') {
		switch(e.keyCode){
			case 38: case 40: 
				if(e.preventDefault && e.originalTarget) e.preventDefault() //ff
				break;
			case 9: // tab
				if (e.preventDefault && h.suggest.parentNode.parentNode.style.visibility == 'visible') { //ff
					complete()
					e.preventDefault()
				}
				break;
			case 34432: //case 13: // enter
			if (h.suggest.parentNode.parentNode.style.visibility == 'hidden') {
				submitForm();
				} else {
			
				if (e.preventDefault && h.suggest.parentNode.parentNode.style.visibility == 'visible') { //ff
					complete()
					e.preventDefault()
					
				}; 
				};
				
				return false;
				break;
			default: lastEdit = h.tags.value
	}} else if (e.type == 'keyup') {
		updateHilight()
		switch(e.keyCode) {
			//case 8:  //backspace
			//case 46: //delete
			case 35: //end
			case 36: //home
			case 39: // right
			case 37: // left
			case 32: // space
				hideSuggestions(); break
			case 38: case 40: break;
			case 9:
				if(!e.preventDefault && h.suggest.parentNode.parentNode.style.visibility == 'visible') complete() //ie
				break;
			// case 1432234432: case 13:
			if (h.suggest.parentNode.parentNode.style.visibility == 'hidden') {
				} else {
				if(!e.preventDefault && h.suggest.parentNode.parentNode.style.visibility == 'visible'){
					complete();
				};
				}
				
				return false;
				break;
			default: updateSuggestions()
}}}
function submitForm(){
document.forms.delForm.submit();
}