/**
 * Copyright 2006  Mipang.com.
 * All Rights Reserved.
 */


/**
 * Mipang's Places Class. version 2
 *
 * SmartPlaceInput{} 
 ** require global.js **
 */


var _mp_spi_top_win = window;

function MP_SmartPlaceInput(initParams){
    /**admin url*/
    this.AdminUrl= "/places/place_admin_xml.ue";
    this.SearchUrl = "/places/place_search_xml.ue";



    if(typeof MIPANG != 'undefined' && typeof MIPANG.location != 'undefined')
	this.main_url = MIPANG.location.scheme+'://'+MIPANG.location.main_host;
    else
	this.main_url = '';


    this.EXT = {};
    this.initialized = false;
    /**init me*/
    this.init(initParams);
}

MP_SmartPlaceInput.prototype.init=function(params){
    /**
      params:
      textfield: 
     */
    if(this.initialized) return;
    
    if(typeof params != 'object')
	return;
    
    var EXT=this.EXT;
    EXT.instance = this;

    EXT.textfield = GetElement(window,params.textfield);
    EXT.textfield.EXT = EXT;


    EXT.MyPlaces = params.places||[];
    EXT.onselect = params.onselect||function(pid,name,pname){};

    EXT.SetSelect = function(pid,name,pname){
	EXT.place_selected = [pid,name];

	var textbox = this.textfield;
	textbox.value = name;
	this.onselect(pid,name,pname);
	RemoveClass(textbox,'pending');
	RemoveClass(textbox,'error');
	AddClass(textbox,'valid');
    };

    EXT.CleanSelect = function(){
	var textbox = this.textfield;
	this.onselect(0,textbox.value,'');
	RemoveClass(textbox,'valid');
    };

    /** place[pd] Define (Ajax Stuff)*/
    EXT.pf = {
	id:0,/**Place ID*/
	name:1,/**Place Name*/
	aka:2,/** Place's Aka */
	aka2:3,
	pname:4/** Parent Place Name*/
    };
    
    /**init selected place*/
    if(params.selected){
	EXT.place_selected = params.selected;
	EXT.SetSelect(params.selected[0],params.selected[1],params.selected[2]?params.selected[2]:'');
    }else
	EXT.place_selected = [0,''];


    this.initialized = true;

    /**init AC_states*/
    AC_states.put(window.name + EXT.textfield.id, new AC_state());

    /**textfield event attach...*/
    this.InitTextbox();
};

MP_SmartPlaceInput.prototype.InitTextbox=function(){
    if(!this.initialized) return;
    
    var win = window;
    var EXT = this.EXT;
    var box = EXT.textfield;

    try{
	if(!box.style) box.setAttribute('style','');
	box.style.MozUserSelect='none';
    }catch(e1){}
    try{
	box.style.unselectable='on';
	box.setAttribute('autocomplete','off');
	box.setAttribute('disableautocomplete',true);
    }catch(e2){}
    
    box.onclick=function(e){
	if(this.placebox_timeout)
	    clearTimeout(this.placebox_timeout);
	if(this.addguide_timeout)
	    clearTimeout(this.addguide_timeout);

	this.placebox_show = false;
	this.addguide_show = false;

	/**hide fist.*/
	this.EXT.instance.HideMyPlaces.call(EXT.instance);
	this.EXT.instance.HideAddGuide.call(EXT.instance);
	this.EXT.instance.AC_HideHints.call(EXT.instance);
	
	this.EXT.instance.ShowMyPlaces.call(EXT.instance);
	
    };
    box.onblur=function(e){

	this.EXT.instance.AC_HideHints.call(EXT.instance);

	if( !this.placebox_show ){
	    if(this.placebox_timeout)
		clearTimeout(this.placebox_timeout);

	    this.EXT.instance.HideMyPlaces.call(EXT.instance);

	}
	if( !this.addguide_show ){
	    if(this.addguide_timeout)
		clearTimeout(this.addguide_timeout);

	    this.EXT.instance.HideAddGuide.call(EXT.instance);
	}
    };

    /**key event*/
    box.onkeyup=function(e){
	e = e ? e : win.event;
	var keycode = EV_GetKeyCode(e);
	
	if( typeof box.oldvalue == 'undefined') box.oldvalue='';

	switch (keycode) {
	case 9:
	case 38:/**up*/ case 40:/**down*/
	case 27:/**esc*/
	case 37:/**left*/ case 39:/**right*/ 
	    return;
	case 188:/** , */
	case 13:/**enter*/
	    if(AC_cancel_keystroke)
		return;
	default:
	}

	if(this.EXT.query_timeout)
	    clearTimeout(this.EXT.query_timeout);
	
	box.oldvalue = box.value;

	this.EXT.CleanSelect();
	
	var key = Trim(this.EXT.textfield.value);
	var domain = 0;

	/**sub query??*/
	if(/^[^,，，]+[,，，]/.test(key) && key.replace(/[,，，].*$/,'') == this.EXT.place_selected[1]  && this.EXT.place_selected[0]){
	    domain = this.EXT.place_selected[0];
	    key = key.replace(/^[^,，，]*[,，，]/,'');
	    this.EXT.place_search_key = key;
	}else
	    this.EXT.place_search_key = key;

	this.EXT.query_timeout = setTimeout(
					    function(){
						EXT.instance.AC_QueryMatchPlaces.call(
										      EXT.instance,
										      key,
										      domain
										      );
					    },300);
    };
    /***/


    box.onkeydown = function(e) {
	return _mp_spi_top_win.AC_OnKeyDown(win, this, e);
    };
    box.onkeypress = function(e) {
	return _mp_spi_top_win.AC_OnKeyPress(win, this, e);
    };
    
    /**
      box.onblur = function() {
      _mp_spi_top_win.AC_OnBlur(win, this);
      };
    */
    
    box.onfocus = function() {
	/**this.EXT.instance.AC_UpdateHints.call(this.EXT.instance);*/
    };
    
    /**
      box.onclick = function() {
      _mp_spi_top_win.AC_UpdateHintsNow(win, this.id);
      };
    */
    

};

MP_SmartPlaceInput.prototype.ShowMyPlaces=function(){
    if(!this.initialized) return;

    var EXT = this.EXT;
    var h = [""];

    h.push('<div class="bdlBlue" style="border-width:1px;border-style:solid;padding:1px;text-align:left;"><div class="bglBlue2" style="padding:5px;">');
    /**h.push('<div style="height:18px;width:240px;">'
	   +(EXT.MyPlaces.length?'从下列地方中选取或':'')
	   +'<span style="color:red;">直接输入地名</span>(<a href="/help/faq.ue#psi" target="_blank">帮助</a>)</div>');
    **/

    h.push('<div style=""><span class="Red">提示</span>：请尽量输入<b>短地名</b>。');
    h.push('<br/>如 西湖，而不是 杭州西湖');
    h.push('<br/>如 临海，而不是 临海市');
    h.push('</div>');
    

    if(EXT.MyPlaces.length && 0){
	h.push('<table cellpadding="0" cellspacing="0" border="0"><tbody><tr><td style="padding:0;vertical-align:top;">');
	h.push('<ul class="pl" style="">');
	
	var cn = Math.ceil(EXT.MyPlaces.length/3);

	for(var i=0;i<EXT.MyPlaces.length;i++){
	    var p=EXT.MyPlaces[i];
	    h.push('<li><span class="l" onclick="javascript:_ge(\''+EXT.textfield.id+'\').EXT.SetSelect('+p[0]+',\''+StrSafeInline(p[1])+'\',\''+StrSafeInline(p[2]?p[2]:'')+'\');">'+HtmlEscape(p[1])+'</span></li>');
	    
	    if(!((i+1)%cn))
		h.push('</ul></td><td style="padding:0;vertical-align:top;"><ul class="pl" style="">');
	}
	
	h.push('</ul>');
	h.push('</td></tr></tbody></table>');
    }else{
	/**
	h.push('<div class="DateTime"><span>很抱歉，还没有你的地方信息<!--，可能是你还没有登录-->；<br/>你可以直接在输入框中输入地名。</span></div>');
	*/

    }
    
    h.push('<div class="ClearBreak"></div></div></div>');
    
    var textfield = EXT.textfield;
    var div = CreateDIV(window, "eps");
    div.innerHTML = h.join("");
    var s = div.style;
    s.zIndex=500;
    if (s.display != "block") {
	s.display = "block";
	s.top = (GetPageOffsetTop(textfield) + textfield.offsetHeight + 0) + "px";
	s.left = GetPageOffsetLeft(textfield) + "px";
    }
    /**s.overflow='auto';*/


    /** build iframe **/
    var iframe = _ge('eps-iframe');
    if(!iframe){
	iframe = document.createElement('iframe');
	iframe.id = 'eps-iframe';
	iframe.frameBorder='0';
	iframe.setAttribute('style','');
	iframe.style.position='absolute';
	document.body.insertBefore(iframe,document.body.firstChild);
    }

    iframe.style.left = div.style.left;
    iframe.style.top = div.style.top;
    iframe.style.width = div.offsetWidth + 'px';
    iframe.style.height = div.offsetHeight + 'px';
    iframe.style.display = '';

    /**event attach*/
    div.onmouseover=function(e){
	var textfield = EXT.textfield;
	if(textfield.placebox_timeout)
	    clearTimeout(textfield.placebox_timeout);
	
	textfield.placebox_show = true;
    };
    div.onmouseout=function(e){
	var textfield = EXT.textfield;
	if(textfield.placebox_timeout)
	    clearTimeout(textfield.placebox_timeout);
	textfield.placebox_timeout = setTimeout(function(){
		textfield.placebox_show=false;
		textfield.EXT.instance.HideMyPlaces.call(textfield.EXT.instance);
	    },200);
    };


};

MP_SmartPlaceInput.prototype.ShowAddGuide=function(){
    if(!this.initialized) return;

    var EXT = this.EXT;
    var textfield = EXT.textfield;

    var key = Trim(this.EXT.textfield.value);
    var domain = 0;

    /**sub query??*/
    if(/^[^,，，]+[,，，]/.test(key) && key.replace(/[,，，].*$/,'') == this.EXT.place_selected[1]  && this.EXT.place_selected[0]){
	domain = this.EXT.place_selected[0];
	key = key.replace(/^[^,，，]*[,，，]/,'');
    }



    var h = [""];

    h.push('<div class="bdlBlue" style="border-width:1px;border-style:solid;padding:1px;text-align:left;"><div class="bglBlue2_" style="padding:5px;background-color:#ffffcc;">');
    
    h.push('找不到这个地方，请尽量输入<b>短地名</b>。');
    h.push('<br/>如 西湖，而不是 杭州西湖');
    h.push('<br/>如 临海，而不是 临海市');
    
    h.push('<br/><br/>也有可能米胖还没有收录&quot;'+HtmlEscape(key)+'&quot;这个地方，<br/>没关系，你可以马上<a href="'+this.main_url+'/places/new?domain='+(domain?domain:'')+'&amp;name='+UrlEncode(key)+'" target="_blank">添加&quot;'+HtmlEscape(key)+'&quot;</a>到米胖。');
    
    h.push('<div class="ClearBreak"></div></div></div>');
    

    var div = CreateDIV(window, "pag");
    div.innerHTML = h.join("");
    var s = div.style;
    s.zIndex=500;
    if (s.display != "block") {
	s.display = "block";
	s.top = (GetPageOffsetTop(textfield) + textfield.offsetHeight + 0) + "px";
	s.left = GetPageOffsetLeft(textfield) + "px";
    }
    /**s.overflow='auto';*/


    /** build iframe **/
    var iframe = _ge('pag-iframe');
    if(!iframe){
	iframe = document.createElement('iframe');
	iframe.id = 'pag-iframe';
	iframe.frameBorder='0';
	iframe.setAttribute('style','');
	iframe.style.position='absolute';
	document.body.insertBefore(iframe,document.body.firstChild);
    }

    iframe.style.left = div.style.left;
    iframe.style.top = div.style.top;
    iframe.style.width = div.offsetWidth + 'px';
    iframe.style.height = div.offsetHeight + 'px';
    iframe.style.display = '';


    /**event attach*/
    div.onmouseover=function(e){
	var textfield = EXT.textfield;
	if(textfield.addguide_timeout)
	    clearTimeout(textfield.addguide_timeout);
	
	textfield.addguide_show = true;
    };
    div.onmouseout=function(e){
	var textfield = EXT.textfield;
	if(textfield.addguide_timeout)
	    clearTimeout(textfield.addguide_timeout);
	textfield.addguide_timeout = setTimeout(function(){
		textfield.addguide_show=false;
		textfield.EXT.instance.HideAddGuide.call(textfield.EXT.instance);
	    },10000);
    };

};
MP_SmartPlaceInput.prototype.HideAddGuide=function(){
    if(!this.initialized) return;
    try{
	ShowElement(GetElement(window,"pag"),false);
	_ge('pag-iframe').style.display = 'none';
    }catch(e){}

};

MP_SmartPlaceInput.prototype.HideMyPlaces=function(){
    if(!this.initialized) return;
    try{
	ShowElement(GetElement(window,"eps"),false);
	_ge('eps-iframe').style.display='none';
    }catch(e){}

};
MP_SmartPlaceInput.prototype.AC_HideHints=function(){
    if(!this.initialized) return;
    try{
	AC_HideHints(window);
    }catch(e){}
};

MP_SmartPlaceInput.prototype.AC_HideHintsNow=function(){
    if(!this.initialized) return;
    try{
	AC_HideHintsNow(window);
    }catch(e){}
};

/**
 * Auto Complete
 */

/**Ajax Stuff*/
MP_SmartPlaceInput.prototype.AC_QueryMatchPlaces=function(keyword,domain){
    /**
      keyworld: piece of place name
      domain: placeID,search in this domain
    */
    if(!this.initialized) return;

    if(!keyword && !domain) return;
    
    var EXT = this.EXT;

    /*************Cache************/
    var places = null;
    if( ( places=AC_CacheLookup(keyword,domain) ) ){
	
	RemoveClass(EXT.textfield,'valid');
	RemoveClass(EXT.textfield,'pending');
	RemoveClass(EXT.textfield,'error');

	this.AC_UpdateMatchs(places);
	
	this.AC_UpdateHints();
	
	return;
	/**use cache data,just return here*/
    }

    /**************END Cache**************/

    /**set callback stuff*/
    EXT.QueryMatchPlaces_onLoad = function(success,rsXML,rsText,params,CBParams){
	RemoveClass(EXT.textfield,'valid');
	RemoveClass(EXT.textfield,'pending');
	RemoveClass(EXT.textfield,'error');

	if(success.code!=0){
	    /**for debug*/
	    /**alert('发生错误(#'+success.code+'):'+success.desc);*/
	    
	    AddClass(EXT.textfield,'error');
	    return;
	}
	/**success.*/
	var places = null;
	try{
	    var doc = rsXML.documentElement;
	    var t = doc.getElementsByTagName('places');
	    var ts = getNodeValue(t[0]);
	    places = eval(ts);
	}catch(e){
	    places = [];
	}

	try{
	if( places[0][0]<=0 && params.q ){
	    this.instance.HideMyPlaces(this.instance);
	    this.instance.AC_HideHints(this.instance);
	    this.instance.ShowAddGuide(this.instance);
	    return;
	}
	}catch(e){}

	this.instance.AC_UpdateMatchs.call(this.instance,places);

	this.instance.AC_UpdateHints.call(this.instance);

	/**cache it*/
	AC_CacheAdd(params.q,places,params.domain);
	
    };
    
    /**do request*/
    var  params={
	action:'Search',
	q:keyword,
	domain:domain
    };

    /**show status*/
    RemoveClass(this.EXT.textfield,'valid');
    RemoveClass(this.EXT.textfield,'error');
    AddClass(this.EXT.textfield,'pending');

    MyAPI.callMethod('QueryMatchPlaces',params,EXT,null,this.SearchUrl);
    
};

MP_SmartPlaceInput.prototype.AC_UpdateMatchs=function(places){
    if(!this.initialized) return;
    
    var EXT =this.EXT;
    var textbox = EXT.textfield;

    var state = AC_GetState(window,textbox.id);
    AssertTrue(state);

    if(places[1] && places[1].length){
	state.match_info.places = places[1];
	state.match_info.match_num = places[0][0];
	state.match_info.match_total = places[0][1];

	if(state.selected_match == -1)
	    state.selected_match = 0;

    }else
	state.clear();

};

MP_SmartPlaceInput.prototype.AC_UpdateHints=function()
{
    if(!this.initialized) return;
    
    var EXT = this.EXT;
    var textbox = EXT.textfield;

    AC_UpdateHints(window,textbox);
    
};

MP_SmartPlaceInput.prototype.AC_RenderHintsWindow=function()
{
    if(!this.initialized) return;

    this.HideMyPlaces();
    this.HideAddGuide();
    
    var EXT = this.EXT;
    var textbox = EXT.textfield;

    if (!AC_IsActiveTextboxId(window, textbox.id)) {
	this.AC_HideHintsNow();
    }
    AC_SetActiveTextboxId(window, textbox.id);

    var win = window;

    var pf = this.EXT.pf;
    
    var state = AC_GetState(win,textbox.id);

    var ListSize = 20; /**be equal to AC_SetSelection()*/

    var key = String(EXT.place_search_key).toLowerCase();

    /**sub query?*/
    var keyOrig = Trim(textbox.value);
    var domain = 0;

    /**sub query??*/
    if(/^[^,，，]+[,，，]/.test(keyOrig) && keyOrig.replace(/[,，，].*$/,'') == EXT.place_selected[1]  && EXT.place_selected[0]){
	domain = EXT.place_selected[0];
    }
    /***/


    AssertTrue(state.match_info && state.match_info.places.length > 0);

    var h =['<div class="bdlBlue" style="border-width:1px;padding:1px;">'];
    
    /** add help **/

    h.push('<div style="background-color:;"><span class="Red">提示</span>：用鼠标选取</div>');

    /********/

    h.push('<div class="ac bglBlue2" style="">');
    for (var i = 0; i < state.match_info.places.length && i < ListSize; i++) {
	var place = state.match_info.places[i];
	Debug("Place: " + place);
	h.push(
	       '<span class="l'
	       + ((i == state.selected_match) ? ' sel" ' : '" ') + 'id="' + 'h_' + i + '">' 
	       + (place[pf.pname]? HtmlEscape(place[pf.pname]+','):'') 
	       + AC_FormatPlace(pf,place,key) + '</span>'
	       );
    }

    if(state.match_info.match_num > ListSize)
	h.push('<span class="l" style="text-align:center;font-weight:bold;color:#666;">. . .</span>');
    
    if(state.match_info.places.length && key!='' && String(state.match_info.places[0][pf.name]).toLowerCase() != key)
	h.push('<span class="l" id="hpa_'+Now()+'" style="font-size:12px;background-color:#ffffcc;padding-top:3px;padding-bottom:3px;"><a class="pale_red" href="'+this.main_url+'/places/new?domain='+(domain?domain:'')+'&amp;name='+UrlEncode(key)+'" target="_blank" style="">添加&quot;'+HtmlEscape(key)+'&quot;到米胖</a></span>');
    
    h.push( '</div></div>');
    var div = CreateDIV(win, "hm");
    if(div.hide_timeout)
	clearTimeout(div.hide_timeout);

    div.innerHTML = h.join("");

    var s = div.style;
    s.zIndex=500;
    if (s.display != "block") {
	s.display = "block";
	s.top = (GetPageOffsetTop(textbox) + textbox.offsetHeight)+'px';
	s.left = GetPageOffsetLeft(textbox)+'px';
    }
    /**s.overflow='auto';*/


    /** build iframe **/
    var iframe = _ge('hm-iframe');
    if(!iframe){
	iframe = document.createElement('iframe');
	iframe.id = 'hm-iframe';
	iframe.frameBorder='0';
	iframe.setAttribute('style','');
	iframe.style.position='absolute';
	document.body.insertBefore(iframe,document.body.firstChild);
    }

    iframe.style.left = div.style.left;
    iframe.style.top = div.style.top;
    iframe.style.width = div.offsetWidth + 'px';
    iframe.style.height = div.offsetHeight + 'px';
    iframe.style.display = '';
    
    
    setTimeout(function(){
	    try{ ScrollIntoView(window,div,"m");}catch(e){}
	},100);


    /**attach event*/

    div.onmouseover = function(e){
	e = e ? e : window.event;
	var src = EV_GetEventTarget(e);
	var info = {};
	var dep=3;
	for(;src && dep--;src=src.parentNode){
	    if(src.id && src.id.indexOf('h_') != -1){
		info.id_prefix = 'h_';
		info.type = 6;/**mouse over event*/
		info.id_n = src.id.substr(2);
		AC_MouseMovementHandler(window,info);
	    }
	}
    };

    div.onclick = function(e){
	e = e ? e : window.event;
	var src = EV_GetEventTarget(e);
	var dep=3;
	for(;src && dep--;src=src.parentNode){
	    if(src.id && src.id.indexOf('hpa_') != -1){
		return true;
	    }
	}
	/**else*/
	AC_Complete(window,textbox);
    };

};




var MPP_windata =[];
function GetWindowData(win)
{
    var data = MPP_windata[win.name];
    if (!data) {
	MPP_windata[win.name] = data =[];
    }
    return data;
}

function ClearWindowData(win_name)
{
    if (MPP_windata[win_name]) {
	MPP_windata[win_name] = null;
    }
}

var AC_cache = {
    table:[],/** Array(30)[ domain,'key',new AC_state() ] , key is LowerCase */
    maxlen:50,
    cursor:0
};
var AC_cancel_keystroke;
var AC_states = new Map();

function AC_state()
{
    this.clear();
}

AC_state.prototype.clear = function()
{
    /**this.match_info = null;*/
    this.match_info = [];
    this.match_info.places = [];
    this.match_info.match_num = 0;
    this.match_info.match_total = 0;

    this.selected_match = -1;
    this.cursor_pos = 0;
};
function AC_GetState(win, id)
{
    var state = AC_states.get(win.name + id);
    AssertTrue(state);
    return state;
}

function AC_GetActiveTextboxId(win)
{
    return GetWindowData(win).AC_active;
}

function AC_SetActiveTextboxId(win, id)
{
    GetWindowData(win).AC_active = id;
}

function AC_IsActiveTextboxId(win, id)
{
    return id == GetWindowData(win).AC_active;
}


function AC_FindPlaceIndex(places, cur_place)
{
    for (var i = 0; i < places.length; i++) {
	if (places[i][0] == cur_place[0]) {
	    /**only check place_id*/
	    return i;
	}
    }
    return -1;
}


function AC_OnKeyDown(win, textbox, e)
{
    try {
	e = e ? e : win.event;
	var keycode = EV_GetKeyCode(e);
	AC_cancel_keystroke = false;
	switch (keycode) {
	case 188:/** , */
	case 9:
	    if (e.shiftKey) {
		break;
	    }
	case 13:
	    if (AC_Complete(win, textbox)) {
		AC_HideHintsNow(win);
		AC_cancel_keystroke = true;
	    }
	    break;
	case 38:
	case 40:
	    if (AC_IsActiveTextboxId(win, textbox.id)) {
		AC_MoveSelection(win, textbox, keycode == 38);
		AC_cancel_keystroke = true;
	    }
	    break;
	case 27:
	    break;
	default:/**
	    AC_UpdateHints(win, textbox);
		*/
	}
	return (!AC_cancel_keystroke);
    }
    catch(ex) {
	DumpException(ex);
    }
}
function AC_OnKeyPress(win, textbox, e)
{
    return (!AC_cancel_keystroke);
}

function AC_OnBlur(win, textbox)
{
    try {
	win.setTimeout('_mp_spi_top_win.AC_OnBlur2(window,"' + textbox.id + '")',
		       200);
    }
    catch(ex) {
	DumpException(ex);
    }
}
function AC_OnBlur2(win, id)
{
    try {
	if (AC_IsActiveTextboxId(win, id)) {
	    AC_HideHints(win);
	}
    }
    catch(ex) {
	DumpException(ex);
    }
}

function AC_MouseMovementHandler(win, info)
{
    if (info.id_prefix == "h_" && info.type == 6) {
	var textbox = GetElement(win, AC_GetActiveTextboxId(win));
	AC_SetSelection(win, textbox, parseInt(info.id_n));
    }
}
function AC_UpdateHints(win, textbox)
{

    var windata = GetWindowData(win);
    if (windata.AC_timeout) {
	win.clearTimeout(windata.AC_timeout);
    }
    windata.AC_timeout =
	win.setTimeout('_mp_spi_top_win.AC_UpdateHintsNow(window,"' + textbox.id +
		       '")', 50);
}

function AC_UpdateHintsNow(win, id)
{
    try {
	GetWindowData(win).timeout = null;
	var textbox = GetElement(win, id);
	var state = AC_GetState(win, textbox.id);

	if (textbox.value && state.match_info.places.length ) {
	    var partial = textbox.value;
	    if (partial.length > 0) {
		state.cursor_pos = 0;

		AC_ShowHints(win, textbox, state,
			     (partial));
		return;
	    }
	}
	AC_HideHintsNow(win);
    }
    catch(e) {
	DumpException(e);
    }
}


function AC_GetPartialName(str, cursor){
    var segment=AC_GetEditSegment(str,cursor);
    var partial=str.substring(segment[0],segment[1]);
    return partial.replace(/\"/g,"");
}
function AC_GetEditSegment(str, cursor)
{
    return[AC_GetEditStart(str, cursor), AC_GetEditEnd(str, cursor)];
}

function AC_GetEditStart(str, cursor)
{
    AssertTrue(cursor <= str.length);
    var good_char = cursor - 1;
    for (var i = good_char; i >= 0; i--) {
	var ch = str.charAt(i);
	if (ch == ',') {
	    break;
	} else {
	    if (!IsSpace(ch)) {
		good_char = i;
	    }
	}
    }
    return good_char;
}

function AC_GetEditEnd(str, cursor)
{
    AssertTrue(cursor <= str.length);
    var i;
    for (i = cursor; i < str.length; i++) {
	var ch = str.charAt(i);
	if (ch == ',' || ch == '"') {
	    break;
	}
    }
    return i;
}

function AC_Complete(win, textbox)
{
    var state = AC_GetState(win, textbox.id);
    if (state.match_info && state.selected_match >= 0
	&& state.selected_match < state.match_info.places.length
	&& state.cursor_pos >= 0) {
	var places = state.match_info.places;
	var selected = state.selected_match;
	AC_CompleteTo(win, textbox, state,places[selected]);
	return true;
    }
    return false;
}

function AC_CompleteTo(win, textbox, state, place)
{
    var cursor = state.cursor_pos;
    if (cursor >= 0) {
	var textstr = textbox.value;
	var EXT = textbox.EXT;
	var pf = EXT.pf;

	if (is_safari) {
	    win.setTimeout(function() {
		    EXT.SetSelect(place[pf.id],place[pf.name],place[pf.pname]);
			   }
			   , 0);
	} else {
	    EXT.SetSelect(place[pf.id],place[pf.name],place[pf.pname]);
	}

	SetCursorPos(win, textbox,
		     place[pf.name].length);
	state.clear();
	return true;
    }
    return false;
}


function AC_MatchSubstring(str, substr)
{
    for (var pos = 0;; pos++) {
	pos = str.indexOf(substr, pos);
	if (pos < 0) {
	    return -1;
	}
	return pos;
	/**
	  if (pos == 0 || !IsLetterOrDigit(str.charAt(pos - 1))) {
	  return pos;
	  }
	*/
    }
}
function AC_MoveSelection(win, textbox, up)
{
    var dir = (up) ? -1 : 1;
    var state = AC_GetState(win, textbox.id);
    AC_SetSelection(win, textbox, state.selected_match + dir);
}

function AC_SetSelection(win, textbox, pos)
{
    var state = AC_GetState(win, textbox.id);
    AssertTrue(textbox && state);
    if (pos != state.selected_match && state.match_info != null && pos >= 0
	&& pos < state.match_info.places.length && pos < 20) {
	state.selected_match = pos;
	AC_RenderHintsWindow(win, textbox, state);
    }
}
function AC_ShowHints(win, textbox, state, str)
{
    var curr_place = null;
    if (state.selected_match > 0 && state.selected_match < state.match_info.places.length) {
	/**curr_place = state.match_info.places[state.selected_match];*/
    }
    if (state.match_info && state.match_info.places.length > 0) {
	state.selected_match = 0;
	if (curr_place) {
	    var new_index =
		AC_FindPlaceIndex(state.match_info.places,
				    curr_place);
	    if (new_index >= 0) {
		state.selected_match = new_index;
	    }
	}
	AC_RenderHintsWindow(win, textbox, state);
    } else {
	AC_HideHintsNow(win);
    }
}

function AC_RenderHintsWindow(win,textbox,state)
{
    try{
	var instance = textbox.EXT.instance;
	instance.AC_RenderHintsWindow.call(instance);
    }catch(e){}
}

function AC_HideHints(win)
{
    var h = GetElement(win,"hm");
    h.hide_timeout = setTimeout("_mp_spi_top_win.AC_HideHintsNow(window)",200);
}

function AC_HideHintsNow(win)
{
    var h = GetElement(win, "hm");
    if (h) {
	ShowElement(h, false);
	try{_ge('hm-iframe').style.display='none';}catch(ex){}
    }
    var active_id = AC_GetActiveTextboxId(win);
    if (active_id) {
	AC_GetState(win, active_id).clear();
    }
    AC_SetActiveTextboxId(win, null);
    if (MPP_windata.AC_timeout) {
	win.clearTimeout(win.AC_timeout);
	MPP_windata.AC_timeout = null;
    }
}


function AC_FormatPlace(pf,place, keyword)
{

    /**aka1*/
    var aka1 = (place[pf.aka] && AC_MatchSubstring(place[pf.aka].toLowerCase(),keyword)!=-1 ? ( '&nbsp<span style="display:inline;color:#888;padding:0;">' +BoldSubstring(place[pf.aka],keyword) + '</span>') : '');
    
    var aka2 = (place[pf.aka2] && AC_MatchSubstring(place[pf.aka2].toLowerCase(),keyword)!=-1 ? ( (place[pf.aka] && aka1 ?',':'&nbsp;') + '<span style="display:inline;color:#888;padding:0;">' +BoldSubstring(place[pf.aka2],keyword) + '</span>') : '');
	    
    return BoldSubstring(place[pf.name], keyword) + aka1 + aka2;
}

function BoldSubstring(str, prefix)
{
    if (prefix != "") {
	var pos = AC_MatchSubstring(str.toLowerCase(), prefix);
	if (pos != -1) {
	    return (HtmlEscape(str.substr(0, pos)) + "<b>" +
		    HtmlEscape(str.substr(pos, prefix.length)) + "</b>" +
		    HtmlEscape(str.substr(pos + prefix.length)));
	}
    }
    return HtmlEscape(str);
}


function AC_CacheLookup(keyword,domain)
{
    var key = String(keyword).toLowerCase();
    domain = domain ? domain : 0;

    for(var i=0;i<AC_cache.table.length;i++){
	if( key == AC_cache.table[i][1] && domain == AC_cache.table[i][0] ){
	    /**get it*/
	    var state = AC_cache.table[i][2];

	    var r =  [ [state.match_info.match_num,state.match_info.match_total]
		    ,state.match_info.places ];
	    return r;
	    
	}
    }

    return null;

}
function AC_CacheAdd(keyword,places,domain)
{

    var key = String(keyword).toLowerCase();
    domain = domain ? domain : 0;
    
    var state = new AC_state();

    if(places[1] && places[1].length){
	state.match_info.places = places[1];
	state.match_info.match_num = places[0][0];
	state.match_info.match_total = places[0][1];

	if(state.selected_match == -1)
	    state.selected_match = 0;
	
	/**replace the old one*/
	var dup=0;
	for(var i=0;i<AC_cache.table.length;i++){
	    if(key == AC_cache.table[i][1] && domain == AC_cache.table[i][0]){
		AC_cache.table[i] = [ domain,key,state ];
		dup++;
	    }
	}
	
	if(!dup){
	    var cur = AC_cache.cursor;
	    var maxlen = AC_cache.maxlen;
	    AC_cache.table[ cur % maxlen ] = null;
	    AC_cache.table[ cur % maxlen ] = [ domain,key,state ];
	    
	    AC_cache.cursor = (cur + 1) % maxlen;
	}
    }
   
}