// Dynamic Script Loading Server Requests
// Call this with URL for request and optional callback function
// If callback function is supplied, place [CB] in the URL where the function name should be substituted
// If cp is set, the callback for the previous request will be cancelled if not yet called
// If cdat is set, it is passed as a second parameter to the callback function
// Note: Make URL unique with a random parameter (&p=Math.random()) to avoid caching
var JSONcbCount=0;
function JSONrequest(url,func,cp,cdat)
{
	var old=document.getElementById('JSONrequestScript');
	if(old) {
		old.parentNode.removeChild(old);
		delete old;
	}
	if(cp && JSONcbCount && window["JSONcb"+(JSONcbCount-1)]) {
		window["JSONcb"+(JSONcbCount-1)]=function(){setTimeout("window['JSONcb"+(JSONcbCount-1)+"']=null;",1);};
	}
	if(func) {
		url=url.replace("[CB]","JSONcb"+JSONcbCount);
		window["JSONcb"+JSONcbCount]=function(data){func(data,cdat);setTimeout("window['JSONcb"+JSONcbCount+"']=null;",1);};
		JSONcbCount++;
	}
	var head=document.getElementsByTagName("head")[0];
	var script=document.createElement("script");
	script.id="JSONrequestScript";
	script.type="text/javascript";
	script.src=url;
	head.appendChild(script);
}


/**
* An autosuggest textbox control.
* @class
* @scope public
*/
function AutoSuggestControl(oTextbox /*:HTMLInputElement*/,
                            oProvider /*:LocProvider*/,
							sAction,
							noSubmit
							) {

    this.hideme = 0;

    this.submitme = 1;

	this.justHidden=false;

    this.Action = sAction;

	this.doSubmit=true;	// submit the form when something is selected
	if(noSubmit || autoSuggestNoSubmit) this.doSubmit=false;

    /**
    * The currently selected suggestions.
    * @scope private
    */
    this.cur /*:int*/ = -1;

    /**
    * The dropdown list layer.
    * @scope private
    */
    this.layer = null;

    /**
    * Suggestion provider for the autosuggest feature.
    * @scope private.
    */
    this.provider /*:LocProvider*/ = oProvider;

    /**
    * The textbox to capture.
    * @scope private
    */
    this.textbox /*:HTMLInputElement*/ = oTextbox;

    /**
    * Timeout ID for fast typers.
    * @scope private
    */
    this.timeoutId /*:int*/ = null;

    /**
    * The text that the user typed.
    * @scope private
    */
    this.userText /*:String*/ = oTextbox.value;

    //initialize the control
    this.init();

}

/**
* Autosuggests one or more suggestions for what the user has typed.
* If no suggestions are passed in, then no autosuggest occurs.
* @scope private
* @param aSuggestions An array of suggestion strings.
* @param bTypeAhead If the control should provide a type ahead suggestion.
*/
AutoSuggestControl.prototype.autosuggest = function(aSuggestions /*:Array*/,
                                                     bTypeAhead /*:boolean*/) {

    //re-initialize pointer to current suggestion
    this.cur = -1;

    //make sure there's at least one suggestion
    if (aSuggestions.length > 0) {
        if (bTypeAhead) {
            this.typeAhead(aSuggestions[0]);
        }

        this.showSuggestions(aSuggestions);
    } else {
        this.hideSuggestions();
    }
};

/**
* Creates the dropdown layer to display multiple suggestions.
* @scope private
*/
AutoSuggestControl.prototype.createDropDown = function() {


    //create the layer and assign styles
    this.layer = document.createElement("div");
    this.layer.className = "suggestions";
    this.layer.style.visibility = "hidden";
    var w=this.textbox.offsetWidth;
    var minw=170;
    if(this.Action=="what") minw=300;
    if(w<minw) w=minw;
    this.layer.style.width = w;
    document.body.appendChild(this.layer);

    //when the user clicks on the a suggestion, get the text (innerHTML)
    //and place it into a textbox
    var oThis = this;
    this.layer.onmousedown =
    this.layer.onmouseup =
    this.layer.onmouseover = function(oEvent) {
        oEvent = oEvent || window.event;
        oTarget = oEvent.target || oEvent.srcElement;

        if (oEvent.type == "mousedown") {
            oThis.textbox.value = oTarget.getAttribute("RealVal");
            oThis.hideSuggestions();
            if(oThis.doSubmit) dogo();
        } else if (oEvent.type == "mouseover") {
            oThis.highlightSuggestion(oTarget);
        } else {
            oThis.textbox.focus();
        }
    };

};

/**
* Gets the left coordinate of the textbox.
* @scope private
* @return The left coordinate of the textbox in pixels.
*/
AutoSuggestControl.prototype.getLeft = function() /*:int*/{

    var oNode = this.textbox;
    var iLeft = 0;

    while (oNode.tagName != "BODY") {
        iLeft += oNode.offsetLeft;
        oNode = oNode.offsetParent;
    }

    return iLeft;
};

/**
* Gets the top coordinate of the textbox.
* @scope private
* @return The top coordinate of the textbox in pixels.
*/
AutoSuggestControl.prototype.getTop = function() /*:int*/{

    var oNode = this.textbox;
    var iTop = 0;

    while (oNode.tagName != "BODY") {
        iTop += oNode.offsetTop;
        oNode = oNode.offsetParent;
    }

    return iTop;
};

/**
* Highlights the next or previous suggestion in the dropdown and
* places the suggestion into the textbox.
* @param iDiff Either a positive or negative number indicating whether
*              to select the next or previous sugggestion, respectively.
* @scope private
*/
AutoSuggestControl.prototype.goToSuggestion = function(iDiff /*:int*/) {
    var cSuggestionNodes = this.layer.childNodes;

    if (cSuggestionNodes.length > 0 && this.userText.length > 0) {
        var oNode = null;
        this.submitme = 0;

        if (iDiff > 0) {
            if (this.cur < cSuggestionNodes.length - 1) {
                oNode = cSuggestionNodes[++this.cur];
            }
        } else {
            if (this.cur > 0) {
                oNode = cSuggestionNodes[--this.cur];
            }
        }

        if (oNode) {
            this.highlightSuggestion(oNode);
            this.textbox.value = oNode.getAttribute("RealVal");
        }
    }
};

/**
* Handles three keydown events.
* @scope private
* @param oEvent The event object for the keydown event.
*/
AutoSuggestControl.prototype.handleKeyDown = function(oEvent /*:Event*/) {
    switch (oEvent.keyCode) {
        case 9: //tab
            //this.goToSuggestion(1);
            this.hideme = 1;
            this.hideSuggestions();
            break;
        case 38: //up arrow
            this.goToSuggestion(-1);
            break;
        case 40: //down arrow 
            this.goToSuggestion(1);
            break;
        case 27: //esc
        	var oThis=this;
        	if(this.Action=="where") setTimeout(function(){oThis.textbox.value=vwhere;oThis.selectRange(0,oThis.textbox.value.length);},10);
         	if(this.Action=="what") setTimeout(function(){oThis.textbox.value=vwhat;oThis.selectRange(0,oThis.textbox.value.length);},10);
			this.textbox.value = this.userText;
            this.selectRange(this.textbox.value.length, 0);
            /* falls through */
        case 13: //enter
            if (this.submitme != 1) {
                this.hideSuggestions();
                this.submitme = 1;
                oEvent.returnValue = false;
                if (oEvent.preventDefault) {
                    oEvent.preventDefault();
                }
                if(oEvent.keyCode==13 && this.doSubmit) dogo();
            } else {
                this.hideSuggestions();
            }
        default:
            this.hideme = 0;
            break;
    }

};

/**
* Handles keyup events.
* @scope private
* @param oEvent The event object for the keyup event.
*/
AutoSuggestControl.prototype.handleKeyUp = function(oEvent /*:Event*/) {

    var iKeyCode = oEvent.keyCode;
    var oThis = this;

    //get the currently entered text
    this.userText = this.textbox.value;

    clearTimeout(this.timeoutId);

    //for backspace (8) and delete (46), shows suggestions without typeahead
    if (iKeyCode == 8 || iKeyCode == 46) {

        this.timeoutId = setTimeout(function() {
            oThis.provider.requestSuggestions(oThis, false);
        }, 250);

        //make sure not to interfere with non-character keys
    } else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode < 46) || (iKeyCode >= 112 && iKeyCode <= 123)) {
        //ignore
    } else {
        //request suggestions from the suggestion provider with typeahead
        this.timeoutId = setTimeout(function() {
            oThis.provider.requestSuggestions(oThis, true);
        }, 250);
    }
};

/**
* Hides the suggestion dropdown.
* @scope private
*/
AutoSuggestControl.prototype.hideSuggestions = function() {
    this.layer.style.visibility = "hidden";
};

/**
* Highlights the given node in the suggestions dropdown.
* @scope private
* @param oSuggestionNode The node representing a suggestion in the dropdown.
*/
AutoSuggestControl.prototype.highlightSuggestion = function(oSuggestionNode) {

    for (var i = 0; i < this.layer.childNodes.length; i++) {
        var oNode = this.layer.childNodes[i];
        if (oNode == oSuggestionNode) {
            oNode.className = "current"
        } else if (oNode.className == "current") {
            oNode.className = "";
        }
    }
};

/**
* Initializes the textbox with event handlers for
* auto suggest functionality.
* @scope private
*/
AutoSuggestControl.prototype.init = function() {

    //save a reference to this object
    var oThis = this;

    //assign the onkeyup event handler
    this.textbox.onkeyup = function(oEvent) {

        //check for the proper location of the event object
        if (!oEvent) {
            oEvent = window.event;
        }

        //call the handleKeyUp() method with the event object
        oThis.handleKeyUp(oEvent);
    };

    //assign onkeydown event handler
    this.textbox.onkeydown = function(oEvent) {

        //check for the proper location of the event object
        if (!oEvent) {
            oEvent = window.event;
        }

        //call the handleKeyDown() method with the event object
        oThis.handleKeyDown(oEvent);
    };

    //assign onblur event handler (hides suggestions)    
    this.textbox.onblur = function() {
    	oThis.justHidden=true;
        oThis.hideSuggestions();
        setTimeout(function(){oThis.justHidden=false;},100);
    };

    //create the suggestions dropdown
    this.createDropDown();
};

/**
* Selects a range of text in the textbox.
* @scope public
* @param iStart The start index (base 0) of the selection.
* @param iEnd The end index of the selection.
*/
AutoSuggestControl.prototype.selectRange = function(iStart /*:int*/, iEnd /*:int*/) {

    //use text ranges for Internet Explorer
    if (this.textbox.createTextRange) {
        var oRange = this.textbox.createTextRange();
        oRange.moveStart("character", iStart);
        oRange.moveEnd("character", iEnd - this.textbox.value.length);
        oRange.select();

        //use setSelectionRange() for Mozilla
    } else if (this.textbox.setSelectionRange) {
        this.textbox.setSelectionRange(iStart, iEnd);
    }

    //set focus back to the textbox
    this.textbox.focus();
};

/**
* Builds the suggestion layer contents, moves it into position,
* and displays the layer.
* @scope private
* @param aSuggestions An array of suggestions for the control.
*/
AutoSuggestControl.prototype.showSuggestions = function(aSuggestions /*:Array*/) {

    var oDiv = null;
    this.layer.innerHTML = "";  //clear contents of the layer
    var what = this.textbox.value.split(" ");
    var matches = new Array();
    for (var i = 0; i < aSuggestions.length; i++) {
        matches[0] = [0];
        matches[1] = [0];
        //Play with the Suggestion to highlight the words that macth words in our array splitting on spaces.
        var Suggestions = aSuggestions[i].split(" ");
        for (var j = 0; j < what.length; j++) {
            for (var k = 0; k < Suggestions.length; k++) {
                if (what[j] != "" && what[j].toLowerCase() == Suggestions[k].toLowerCase().substring(0, what[j].length) && this.Action == "GetKeywords") //Only for keywords
                {
                    matches[0][k] = 1;
                    matches[1][k] = what[j].length;
                }
            }
        }
        var myhtml = "";
        for (var k = 0; k < Suggestions.length; k++) {
            if (matches[0][k] == 1) {
                myhtml = myhtml + "<font style='color:#ff0000;FONT-WEIGHT:bold;'>" + Suggestions[k].substring(0, matches[1][k]) + "</font>" + Suggestions[k].substring(matches[1][k], Suggestions[k].length) + " ";
            }
            else {
                myhtml = myhtml + Suggestions[k] + " ";
            }
        }
        oDiv = document.createElement("div");
        oDiv.setAttribute("RealVal", aSuggestions[i]);
        this.layer.appendChild(oDiv);
        this.layer.childNodes[i].innerHTML = myhtml;
    }
    this.layer.style.left = this.getLeft() + "px";
    this.layer.style.top = (this.getTop() + this.textbox.offsetHeight) + "px";

    if (this.hideme != 1) {
        this.layer.style.visibility = "visible";
    }
};

/**
* Inserts a suggestion into the textbox, highlighting the 
* suggested part of the text.
* @scope private
* @param sSuggestion The suggestion for the textbox.
*/
AutoSuggestControl.prototype.typeAhead = function(sSuggestion /*:String*/) {

    //check for support of typeahead functionality
    if (this.textbox.createTextRange || this.textbox.setSelectionRange) {
        var iLen = this.textbox.value.length;
        this.textbox.value = sSuggestion;
        this.selectRange(iLen, sSuggestion.length);
    }
};

/**
* Provides suggestions for state/province names.
* @class
* @scope public
*/
function LocProvider() {}
function SuggProvider() {}

var autoSuggestServer="http://www.socalgaypages.com";	// default to same server
var autoSuggestCountry=3;	// default to 0 for country
var autoSuggestNoState=0;	// default to showing state
var minWhatLength=1;		// minimum length for "what" search
var autoSuggestNoSubmit=false;	// suppress auto-submit if true

/**
* Request suggestions for the given autosuggest control. 
* @scope protected
* @param oAutoSuggestControl The autosuggest control to provide suggestions for.
*/
LocProvider.prototype.requestSuggestions = function(oAutoSuggestControl /*:AutoSuggestControl*/,
                                                            bTypeAhead /*:boolean*/) {

	var txt=oAutoSuggestControl.userText;
	if(txt.length<1) return;

	var params="f=JW"+encodeURIComponent(txt)+"&go=[CB]&p="+Math.random();
	params+="&z="+autoSuggestCountry;
	if(autoSuggestNoState) params+="&s=1";
	
	JSONrequest(autoSuggestServer+"/sys/pageserver.dll?"+params,
		function(r){
			if(!r || !r.length) return;
			if(r.length>35) r=r.slice(0,35);

			var c=[];
			for(i=0;i<r.length;i++) {
				c[i]=r[i][0];
			}
            oAutoSuggestControl.autosuggest(c, false);	
		},true);
};

SuggProvider.prototype.requestSuggestions = function(oAutoSuggestControl /*:AutoSuggestControl*/,
                                                            bTypeAhead /*:boolean*/) {

	var txt=oAutoSuggestControl.userText;
	if(txt.length<minWhatLength) return;

	var loc="";
	if(document.vform && document.vform.where) loc=document.vform.where.value;
	else if(document.fstandard) loc=document.fstandard.where.value;
	else loc=vwhere;
	var sp="";
	if(typeof sectionPath=="string") {
		sp=sectionPath;
		if(sp.toLowerCase()=="/index" || sp.toLowerCase()=="/front-cover") sp="";
	}

    var params="pa="+encodeURIComponent(loc)+sp+"&f=jwhat[CB]&go="+encodeURIComponent(txt)+"&p="+Math.random();

	JSONrequest(autoSuggestServer+"/sys/pageserver.dll?"+params,
		function(r){
			if(!r || !r.length) return;
			if(r.length>30) r=r.slice(0,30);
			oAutoSuggestControl.autosuggest(r, false);
		},true);
};

