String.prototype.escRegExp = function(){ return this.replace(/[\\$*+?()=!|,{}\[\]\.^]/g,'\\$&') }
String.prototype.unescHtml = function(){ var i,t=this; for(i in e) t=t.replace(new RegExp(i,'g'),e[i]); return t }
function Suggestions() { this.length=0; this.picked=0 }
var suggestions = new Suggestions()
var tagSearch='', lastEdit=''
var h={}, sections=[{},{},{},{},{},{}], selected={}, currentTag={}, e={'&lt;':'<','&gt;':'>','&amp;':'&','&quot;':'"'}

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

////////////////////////////allenday
var req;

function completeValue(tag) { var tagArray=h.tags.value.split(' ')
	if(typeof tag == 'undefined') tag = suggestions[suggestions.picked].value // 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();
}

function makeTagValue(parent, tag, value, js) {
	parent.appendChild(document.createTextNode(' '))
	var obj = document.createElement('a')
	////var br = document.createElement('br')
	obj.className = 'tag'
	obj.setAttribute('href','javascript:'+js+'("'+value.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)
	////parent.appendChild(br)
	return obj
}

function processReqChange() {
    // only if req shows "loaded"
    if (req.readyState == 4) {
        // only if "OK"
        if (req.status == 200) {
		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
            // ...processing statements go here...
            dasTerm = new Array();
            var dom = req.responseXML;
            var types = dom.documentElement.getElementsByTagName("item");
            for (var i = 0; i < types.length && i < 10; i++) {
//////
		var k = types[i].firstChild.firstChild.nodeValue;
		var v = types[i].lastChild.firstChild.nodeValue;
//		if(tagHash[ k ])  continue // do not suggest already typed tag
		suggestions[suggestions.length] = makeTagValue(h.suggest, k, v, 'completeValue')
		suggestions[suggestions.length].value = v;
		suggestions.length++
//////
            }
		if (suggestions.length > 0) showSuggestions()
		else hideSuggestions()

        } else {
            alert("There was a problem retrieving the XML data:\n" +
                req.statusText);
        }
    }
}

function loadTerms(name) {
        url = "/service/search/tag_ontology?term=" + name + "*";
	req = false;
    // branch for native XMLHttpRequest object
    if(window.XMLHttpRequest) {
    	try {
			req = new XMLHttpRequest();
        } catch(e) {
			req = false;
        }
    // branch for IE/Windows ActiveX version
    } else if(window.ActiveXObject) {
       	try {
        	req = new ActiveXObject("Msxml2.XMLHTTP");
      	} catch(e) {
        	try {
          		req = new ActiveXObject("Microsoft.XMLHTTP");
        	} catch(e) {
          		req = false;
        	}
		}
    }
	if(req) {
		req.onreadystatechange = processReqChange;
		req.open("GET", url, true);
		req.send( null );
	}
}
////////////////////////////allenday


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){
		if ( txt.length >= 3 ) {
			loadTerms( txt );
		}

//		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) {
				//del.icio.us had this inverted joystick-style, nothanks -- allenday
				case 40: suggest((suggestions.picked + 1) % suggestions.length); break
				case 38: suggest(suggestions.picked == 0 ? suggestions.length - 1 : suggestions.picked - 1); break
				//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()
					completeValue()
					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()
					completeValue()
					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
				if(!e.preventDefault && h.suggest.parentNode.parentNode.style.visibility == 'visible') completeValue() //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();
					completeValue();
				};
				}
				
				return false;
				break;
			default: updateSuggestions()
}}}
function submitForm(){
document.forms.delForm.submit();
}
