// Autocomplete implementation for webmail and wmail
// Author: Marijn Weehuizen		Dec 2006


// In memory addressbook data structure
var address_book;

// Data pertaning to currently active autocompletion
var autocomplete;

var init_autocomplete=ac_pageload;

var use_cache=false;
var use_shortlist=false;
var cache_array=[];

ac_scriptload();

// ----------------------------
// -- Initialisation --
// ----------------------------
function ac_scriptload(){
	address_book = new Object;
	autocomplete = new Object;
	cache_array[1]= new Object; // cache;	// autocomplete cache
}
function ac_pageload(){
	var x;
	x=dge('to_field'); 
	if (x) ac_register_ctl(x, "default source");	
	x=dge('cc_field');
	if (x) ac_register_ctl(x, "default source");	
	x=dge('bcc_field') 
	if (x) ac_register_ctl(x, "default source");	
	if(!address_book.data){
		// invalid check as it matches empty address book. dogh!
		//download_addressbook();
	}
	autocomplete.selected=0;
}
function ac_register_ctl(ctl,src){
	add_event(ctl,'keydown',ac_keydown);
	add_event(ctl,'blur',ac_blur);
	add_event(ctl,'focus',ac_focus);
}
function download_addressbook()
{
	alert("starting background abk download (unimplemented)");
}

// ----------------------------
// -- Autocompletion event handling --
// ----------------------------

function ac_keydown(e) {
	if (!e) var e=window.event;
	generalise_event_info(e);
	var defaults=true;
	switch(e.keyCode)
	{
		case 9: case 13:		// 9=TAB // 13=ENTER
			if (ac_docomplete(e))
				defaults=false;
			break;
		case 27:				// ESC
			ac_escape(e);
			defaults=false;
			break;
		case 38:case 40:		// 38=uparrow 40=downarrow
			ac_arrowkey(e)
			break;
		case 37:case 39:		// 37=leftarrow 40=rightarrow
		default:
			ac_defaultkey(e)
			break;
	}			
	return defaults;
}
function ac_blur(e) { 
	ac_hide(autocomplete); 
}
function ac_focus(e) { 
	if (!e) var e=window.event;
	generalise_event_info(e);
	ac_defaultkey(e); 
}

function ac_dd_mousemove(e) {
	if (!e) var e=window.event;
	generalise_event_info2(e);
	var x=se(e);
	if (x.id.indexOf('i_')!=0) return;
	var ac=autocomplete;
	ac.selected=x.id.substr(2);
	ac_show(ac.ctl,ac);
}
function ac_dd_mouseup(e) {
	if (!e) var e=window.event;
	generalise_event_info2(e);
	var x=se(e);
	if (x.id.indexOf('i_')!=0) return;
	var ac=autocomplete;
	ac.selected=x.id.substr(2);
	ret=ac_complete(ac.ctl,ac,',');
	focus_ctl=ac.ctl;
	setTimeout('return_focus();',10);
}
function ac_dd_focus(e) {
	if (!e) var e=window.event;
	generalise_event_info2(e);
	var x=se(e);
	if (x.id.indexOf('ac')!=0) return;
	var ac=autocomplete;
	ac.cancelhide=true;
}
function ac_dd_blur(e) {
	if (!e) var e=window.event;
	generalise_event_info2(e);
	var x=se(e);
	if (x.id.indexOf('ac')!=0) return;
	var ac=autocomplete;
	ac_hide(ac);
}

var focus_ctl;
function return_focus(){
	var oldpos=cursor_position(focus_ctl);
	setCaretPosition(focus_ctl,oldpos>0?oldpos:9999);
}


// -- Core autocomplete functionality --
function ac_defaultkey(e){
	// run main ac trough timer to catch multiple keys and provide us access to
	// text area contents
	setTimeout('ac_defaultkey_delayed("'+e.target.id+'")',50);
	autocomplete.ctl=e.target;
}
function ac_defaultkey_delayed(id){
	var ac=autocomplete;
	var textarea=dge(id);
	if (textarea.value.length==0) return ac_hide(ac);
	var posn=cursor_position(textarea);
	if(posn==0) return ac_hide(ac);
	var txt=relevantText(textarea.value,posn);
	if(txt.length==0) return ac_hide(ac);
	var entries=ac_lookup_string(txt, address_book, ac);
	if (entries==0) return ac_hide(ac);
	
	ac_show(textarea,ac);
}
// -- Additional autocomplete functionality --
function ac_arrowkey(e){
	var new_selected = autocomplete.selected + (e.keyCode==38?-1:+1);
	if (new_selected<0 || new_selected>autocomplete.displayed_length)
		return;
	autocomplete.selected=new_selected;
	ac_show(e.target,autocomplete);
}

function ac_escape(e){
	var ac=autocomplete;
	ac_hide(ac);
}

function ac_docomplete(e){
	var ac=autocomplete;
	ret=ac_complete(e.target,ac,',');
	ac_hide(ac);
	if (ret){
		focus_ctl=ac.ctl;
		setTimeout('return_focus();',10);
	}
	return ret;
}


// ----------------------------
// --- Addressbook lookup ---
// ----------------------------

// --- lookup autocomplete data (optionally cached, retrieve data on demand?) ---
function ac_lookup_string(lookup_text,abk,ac)
{
	if (!abk.data) return 0;
    lookup_text=lookup_text.toLowerCase();
    var e=split_address(lookup_text);
    var name=e[0], email=e[1];
    if(!name&&!email) return 0;
    var ret=[];
    ret.name=name; ret.email=email;
	if(!use_cache){
		ret.match=abk_match_addresses(abk.data,ret.name,ret.email);
	}else{
		var mycache=cache_array[1];
		var q=mycache.find(lookup_text);
		if(l){
			ret.match=q;
		}else{
			for(var i=lookup_text.length-1;i>0;i--){
				var n=lookup_text.substr(0,i);
				q=mycache.find(n);
				if(q) break;
			}
			var db=(q!=null)?q:abk.data;
			ret.match=abk_match_addresses(db,ret.name,ret.email);
			mycache.add(lookup_text,result)
		}
	}
    ac.search=ret;
    return ret.match.length;
}

// --- autocomplete actual data comparison ---
function abk_match_addresses(db,xname,xemail)
{
	var ret=[];
	for(var i=0;i<db.length;i++){
		var entry=db[i], match=false;
		// if(invalid for some reason) continue;

		var email=entry.email.toLowerCase();
		if(xemail && email.indexOf(xemail)==0) match=true;

		var fullname=entry.name.toLowerCase();
		var nickname=entry.nick.toLowerCase();
		if(xname){
			if(fullname && mystrstr(fullname,xname)>=0 ) match=true;
			if(use_shortlist&&nickname && mystrstr(nickname,xname)>=0 ) match=true;
			if(email.indexOf(xname)==0) match=true;
		}
		if (match)
			ret[ret.length]=entry;
	}
	return ret;
}

// --- Actual display of the appropriate autocomplete div ---
function ac_show(ctl,ac)
{
    var data=[];
    var mymatch=ac.search.match;
    var total_adr=mymatch.length;
	if (total_adr==0)
		return;
    if(ac.selected>=total_adr) 
    	ac.selected=total_adr-1;

    var txt,max_adr=7;
    for(var i=0;i<total_adr&&i<max_adr;i++){
        var abk_entry=mymatch[i];
		if (use_shortlist&&(abk_entry.nick!=abk_entry.email) && abk_entry.shortlist)
        	txt=bold_substring(abk_entry.nick,ac.search.name);
        else
        	txt=format_entry(abk_entry,ac.search);
        var tmp1="";
        var tmp2="";
		if(i==ac.selected) tmp1=" sel";
		ac.displayed_length=i;
        data.push('<span style="'+tmp2+'" class="l'+tmp1+'" id="i_'+i+'">'+txt+"</span>");
    }
 	var dropdown=get_element("ac");    
 	if (!dropdown.ac_init){
		add_event(dropdown,'mousemove',ac_dd_mousemove);		
		add_event(dropdown,'mousedown',ac_dd_mouseup);		
		add_event(dropdown,'focus',ac_dd_focus);		
		add_event(dropdown,'blur',ac_dd_blur);		
 		dropdown.ac_init='true';
 	}
    dropdown.innerHTML=data.join('');
	pos_dropdown_by_ctl(dropdown,ctl)
	ac.active=true;
}

// --- do the autocompletion ---
function ac_complete(ctl,ac,sep) 
{
	var txt=ctl.value;
	var posn=cursor_position(ctl);
    if(!ac.active) return false;

	var new_address=ac_format_address(ac.search.match[ac.selected]);
	var cur=get_current_chunk(txt,posn,find_quoted_chunks(txt));
	var sep2="";
	if(cur[1]==txt.length || txt.charAt(cur[1])!="," && txt.charAt(cur[1])!=";")
		sep2=sep+" ";
	var new_txt=txt.substring(0,cur[0])+new_address+sep2+txt.substring(cur[1]);
	var new_posn=cur[0]+new_address.length+sep2.length;
	ctl_set(ctl,new_txt,new_posn);
	
	return true;
}

// --------------------------------------
// -- Autocomplete supporting functionality ---

function relevantText(all_text,cursor_posn){
    var quoted_chunks=find_quoted_chunks(all_text);						// returns array of begin/end pairs
    var chunk=get_current_chunk(all_text,cursor_posn,quoted_chunks);
    var tmp=all_text.substring(chunk[0],chunk[1]);
    return tmp.replace(/\"/g,"")
}
function format_entry(entry,srch){
    var c= (entry.name!="") ? '"'+replace_quotes(entry.name)+'"' : "";
    var d=" <"+entry.email+">";
 
    return bold_substring(c,srch.name) + bold_substring(d,srch.email?srch.email:srch.name);
}
function bold_substring(a,b){
    if(b!=""){
        var c=mystrstr(a.toLowerCase(),b);
        if(c!=-1){
            return xencode(a.substr(0,c))+"<b>"+xencode(a.substr(c,b.length))+"</b>"+xencode(a.substr(c+b.length))
        }
    }
    return xencode(a)
}
function abk_entry(nick,name,email,shortlist,instant,nused){		// Add single addressbook entry
	if (!address_book.data)
		address_book.data=[];
    var a=new Object;
    a.name=name; a.email=email;a.nick=nick;
    a.shortlist=shortlist; a.instant=instant; a.nused=nused;
	a.shortlist=instant;	// We don't really haveshortlist here (in webmail) but use instant as pretend shortlist 
	address_book.data.push(a);
}

function ac_hide(ac){
	ac.cancelhide=false;
	setTimeout('hide_now();',50);
}
function hide_now(){
	ac=autocomplete;
	if(ac.cancelhide==true) return;
	ac.active=false;
	ac.selected=0;
	hide("ac");
}

function ac_format_address(x){
    var name=x.name;
    name=clean_whitespace(name);
    return(name!=""?'"'+name+'" ':"")+"<"+x.email+">";
}
function ctl_set(ctl,txt,posn){
    ctl.value=txt;
    ctl_set_cursor(ctl,posn);
}
function ctl_set_cursor(ctl,posn){
    if(def(ctl.selectionEnd)&&def(ctl.selectionStart)){
        ctl.selectionStart=posn;
        ctl.selectionEnd=posn
    } else if(document.selection&&ctl.createTextRange){
        var r=ctl.createTextRange();
        r.collapse(true);
        r.move("character",posn);
        r.select()
    }
}

// ---



