
Type.registerNamespace('MySpace.Common');

MySpace.Common.FriendSuggest = function(element){
    MySpace.Common.FriendSuggest.initializeBase(this, [element]);
}
MySpace.Common.FriendSuggest.prototype = {

	_FriendSuggestInstance: null,
	_debug: false,
	_startms: null,
	_singleItemHeight: 25,
    _localMatches : null,
	_localRendered : [],
    _helpMsg : null,
	_inputLength : 0,
	_highlightIndex : 0,
	_idAs: null,
	
	_startVis : 0,
	_endVis : 0,
	_visibleItems : 0,
	_shifted : 0,
	_visibleIndex : 0,	
	_sortOrder: 0,
	
	_cache : null,
	_recentCache : [],
	
	
	//Default options
	_varname:"input", 
	_className:"autoComplete", 
	_wrapperDivClass:"autoCompleteWrapper", 
	_timeout:2500, 
	_delay:500, 
	_offsety:-5, 
	_showNoResults:true,
	_hideTimeout: null,
	_compareA1Handler: null,
	
	//User Options
	_clientCachedFriends: null,
	_focus: null,
	_displayLimit: null,
	_parameterMapper: null,
	_browseMode: null,
	_displayLimit: null,
	_displayFooter: null,
	_displaySort: null,
	_ownerDiv: null,
	_resize: null,
	_callback: null,
	_displayRecentList: null,
	_instantClearHandler: null,
	ResetHandler: null,
	_setSuggestionsHandler: null,
	_imgField: null,
	_a1Field: null,
	_a2Field: null,
	_Div: null,
	_highlightedFriends: [],
	_helpDiv: null,
	_suggestionsCount: 0,
	_imageUserId: null,
	_notingUserId: null,
	_unprocessedFriends: [],
	_totalFriendCount: 0,
	_highlightWatcherHandler: null,
	_clickedFriendHandler: null,
	_processedFriendCount: 0,
	_enableTextTags: true,
	
	//Default properties
	get_FriendSuggestInstance: function(){
		return this._FriendSuggestInstance;
	},
	set_FriendSuggestInstance: function(value){
		this._FriendSuggestInstance = value;
	},
	
	get_debug: function(){
		return this._debug;
	},
	set_debug: function(value){
		this._debug = value;
	},
	
	get_varname: function(){
		return this._varname;
	},
	set_varname: function(value){
		this._varname = value;
	},
	
	get_className: function(){
		return this._className;
	},
	set_className: function(value){
		this._className = value;
	},
	
	get_wrapperDivClass: function(){
		return this._wrapperDivClass;
	},
	set_wrapperDivClass: function(value){
		this._wrapperDivClass = value;
	},
	
	get_timeout: function(){
		return this._timeout;
	},
	set_timeout: function(){
		this._timeout = value;
	},
	
	get_delay: function(){
		return this._delay;
	},
	set_delay: function(value){
		this._delay = value;
	},
	
	get_offsety: function(){
		return this._offsety;
	},
	set_offsety: function(value){
		this._offsety = value;
	},
	
	get_showNoResults: function(){
		return this._showNoResults;
	},
	set_showNoResults: function(value){
		this._showNoResults = value;
	},
	
	get_noresults: function(){
		return this._noresults;
	},
	set_noresults: function(value){
		this._noresults = value;
	},
	
	get_clientCachedFriends: function(){
		return this._clientCachedFriends;
	},	
	set_clientCachedFriends: function(value){
		this._clientCachedFriends = Sys.Serialization.JavaScriptSerializer.deserialize(value);
	},
	
	set_focus: function(){
		return this._focus;
	},
	get_focus: function(value){
		this._focus = value;
	},
	
	get_displayLimit: function(){
		return this._displayLimit;
	},
	set_displayLimit: function(value){
		this._displayLimit = value;
	},
	
	get_parameterMapper: function(){
		return this._parameterMapper;
	},
	set_parameterMapper: function(value){
		this._parameterMapper = value;
	},
	
	get_browseMode: function(){
		return this._browseMode;
	},
	set_browseMode: function(value){
		this._browseMode = value;
	},
	
	get_displayLimit: function(){
		return this._displayLimit;
	},
	set_displayLimit: function(value){
		this._displayLimit = value;
	},
	
	get_displayFooter: function(){
		return this._displayFooter;
	},
	set_displayFooter: function(value){
		this._displayFooter = value;
	},
	
	get_displaySort: function(){
		return this._displaySort;
	},
	set_displaySort: function(value){
		this._displaySort = value;
	},
	
	get_ownerDiv: function(){
		return this._ownerDiv;
	},
	set_ownerDiv: function(value){
		this._ownerDiv = value;
	},
	
	get_resize: function(){
		return this._resize;
	},
	set_resize: function(value){
		this._resize = value;
	},
	
	get_callback: function(){
		return this._callback;
	},
	set_callback: function(value){
		this._callback = value;
	},
	
	get_displayRecentList: function(){
		return this._displayRecentList;
	},
	set_displayRecentList: function(value){
		this._displayRecentList = value;
	},
	
	get_helpMsg: function(){
		return this._helpMsg;
	},
	set_helpMsg: function(value){
		this._helpMsg = value;
	},
	
	get_noResults: function(){
		return this._noResults;
	},
	set_noResults: function(value){
		this._noResults = value;
	},
	
	get_idAs: function(){
		if (typeof(this._idAs) !== "string"){
			if ($get(this._idAs)){
				this._idAs = $get(this._idAs);
				
				return this._idAs;
			}
			else
				return null;
		}
		else
			return null;
	},
	set_idAs: function(value){
		this._idAs = value;
	},
	
	get_localMatches: function(){
		return this._localMatches;
	},
	set_localMatches: function(value){
		this._localMatches = value;
	},
	
	get_instantClearHandler: function(){
		return this._instantClearHandler;
	},
	set_instantClearHandler: function(value){
		this._instantClearHandler = value;
	},
	
	getResetHandler: function(){
		return this.ResetHandler;
	},
	setResetHandler: function(value){
		this.ResetHandler = value;
	},
	
	get_setSuggestionsHandler: function(){
		return this._setSuggestionsHandler;
	},
	set_setSuggestionsHandler: function(value){
		this._setSuggestionsHandler = value;
	},
	
	get_a1Field: function(){
		return this._a1Field;
	},
	set_a1Field: function(value){
		this._a1Field = value;
	},
	
	get_a2Field: function(){
		return this._a2Field;
	},
	set_a2Field: function(value){
		this._a2Field = value;
	},
	
	get_imgField: function(){
		return this._imgField;
	},
	set_imgField: function(value){
		this._imgField = value;
	},
	
	get_inputLength: function(){
		return this._inputLength;
	},
	set_inputLength: function(value){
		this._inputLength = value;
	},		
	
	get_suggestionsCount: function(){
		return this._suggestionsCount;
	},
	set_suggestionsCount: function(value){
		if (this._suggestionsCount !== value){
			this._suggestionsCount = value;
		
			this.raisePropertyChanged("_suggestionsCount");
		}
	},
	
	get_clearSuggestionsHandler: function(){
		return this._clearSuggestionsHandler;
	},
	set_clearSuggestionsHandler: function(value){
		this._clearSuggestionsHandler = value;
	},
	
	get_notingUserId: function(){
		return this._notingUserId;
	},
	set_notingUserId: function(value){
		this._notingUserId = value;
	},
	
	get_imageUserId: function(){
		return this._imageUserId;
	},
	set_imageUserId: function(value){
		this._imageUserId = value;
	},
	
	get_enableTextTags: function(){
		return this._enableTextTags;
	},
	set_enableTextTags: function(value){
		this._enableTextTags = value;
	},
	
	
	//EVENTS
	
	add_friendsLoaded: function(handler){
		this.get_events().addHandler("friendsLoaded", handler);
	},
	remove_friendsLoaded: function(handler){
		this.get_events().removeHandler("friendsLoaded", handler);	
	},

	
	_raiseEvent : function(eventName, eventArgs) {
		var handler = this.get_events().getHandler(eventName);
		if (handler) {
			if (!eventArgs) {
				eventArgs = Sys.EventArgs.Empty;
			}
			handler(this, eventArgs);
		}
	},
		
		
	initialize: function(){
		
		//Attach events
		$addHandlers(this.get_element(), {keyup:this.onKeyUp,keydown:this._onKeyDown,focus:this.ShowHelp}, this);
		
		//Window and Document events
		//$addHandlers(window, {resize:this._onResize}, this);
		$addHandlers(document.body, {click:this.HideAll}, this);		
		this.set_setSuggestionsHandler(Function.createDelegate(this, this._setSuggestionsLocal));
		this.set_clearSuggestionsHandler(Function.createDelegate(this, this.ClearSuggestions));
		
		var idAsID = "as_" + this.get_element().id;
		this.set_idAs(idAsID);	
		this._compareA1Handler = Function.createDelegate(this, this._compareA1);
		this._highlightWatcherHandler = Function.createDelegate(this, this._highlightWatcher);
		this._clickedFriendHandler = Function.createDelegate(this, this._clickedFriend);
		
		if(this.get_focus()){
			this.get_element().focus();
		}
		
		this.get_element().setAttribute("autocomplete","off");
		this._startTimer();
		this._setSuggestionsLocal(this.get_clientCachedFriends());
		this._endTimer("set suggestions local");
		
		
	},
	
	
	//PUBLIC FUNCTIONS
	AddToRecentCache: function(obj){
		if (!Array.contains(this._recentCache, obj))
		{
			Array.add(this._recentCache, obj);			
			
			if (this._recentCache.length > 5)
				Array.dequeue(this._recentCache);
		}
	},
	
	HardReset: function(){
		this.set_localMatches(this._cache);
		this.get_element().value = "";
		this.set_inputLength(0);
		this._highlightIndex = 0;
	},
	
	Reset: function(){
		this.get_element().value = "";
		this.set_inputLength(0);
		this._highlightIndex = 0;
	},
	
	//PRIVATE FUNCTIONS
	
	RetrieveFriendList: function(canTagOwner){
	if (typeof(canTagOwner) === "undefined")
	    canTagOwner = true;
	    
		var processDelegate = Function.createDelegate(this, this._processFriendList);
		
		MySpace.Web.Modules.PhotoAlbums.Services.PhotoNotes.GetFriendsList(this.get_notingUserId(), canTagOwner, this.get_imageUserId(), processDelegate, processDelegate);
	},
	
	_processFriendList: function(data){
		if (data !== null){
			var friendList = Sys.Serialization.JavaScriptSerializer.deserialize(data);
		
			this._setSuggestionsLocal(friendList);
			this.ShowHelp(friendList.length);
		}
	},
	
	_onResize: function(e){
		if (this._helpDiv)
			this._layout(this._helpDiv);	
		else if (this._idAs)
			this._layout(this._idAs);	
	},
	
	_layout: function(div){
		var pos = Sys.UI.DomElement.getLocation(this.get_element());
		
		if (typeof(div) === "string")
			div = $get(div);
		
		var divStyle = div.style;
		
		if (this._helpDiv !== null && div.id === this._helpDiv.id) { // position help div
			if (browser.isIE) {
				divStyle.width = (this.get_element().offsetWidth + 2) + "px";
				divStyle.left = (pos.x+1) + "px";
				divStyle.top 		= ( pos.y + this.get_element().offsetHeight + this.get_offsety() + 7) + "px";
			} else {
				divStyle.width = (this.get_element().offsetWidth - 4) + "px";
				divStyle.left = (pos.x -1) + "px";
				divStyle.top 		= ( pos.y + this.get_element().offsetHeight + this.get_offsety() + 5) + "px";
			}		
		} 
		else if (div.id === this.idAs) { // position ac wrapper
			if (browser.isIE) {
				divStyle.top = ( pos.y + this.get_element().offsetHeight + this.get_offsety() + 10) + "px";
				divStyle.left = (pos.x+1) + "px";
				divStyle.width 	= (this.get_element().offsetWidth + 13) + (40) + "px";
			} else {
				divStyle.top = ( pos.y + this.get_element().offsetHeight + this.get_offsety() + 7) + "px";
				divStyle.left = (pos.x-1) + "px";
				divStyle.width 	= (this.get_element().offsetWidth+11) + (40) + "px";
			}
		}
	},
	
	ShowHelp : function(totalFriends){		
		if (this.get_idAs() === null)
		{
			if (this.get_browseMode()){
				this._createList(this._cache);
				
			}
			else{
				if (this._helpDiv) this._helpDiv.parentNode.removeChild(_helpDiv);
				
				var helpDiv = MySpace.Common.FriendSuggest.CreateElement("div", {id:"helpDiv", className:"fullHelp"},this.get_helpMsg(), true);
				
				document.getElementsByTagName("body")[0].appendChild(helpDiv);	
				this._layout(helpDiv);
				this.ResetHelpTimeout();
				this._helpDiv = $get("helpDiv");
			}
		}
		else
		{
			this._createList(this.get_localMatches());
		}
	},	
	//cross browser tab catch implementation - yuk
	_onKeyDown: function(e){
		
		var bubble = true;
		switch(e.keyCode)
		{
			case Sys.UI.Key.enter:
				if (this.get_localMatches().length === 1 && this.get_enableTextTags() === false){
					this.get_localMatches()[0]._clickedFriend();
				}
				bubble = false;
				break;
			case Sys.UI.Key.esc:
				this.ClearSuggestions();
				break;
			
		}
		
		return bubble;
	},
	onKeyUp: function(e){
		var bubble = true;
		switch(e.keyCode){
			case Sys.UI.Key.up:
				this._changeHighlight(e.keyCode);
				bubble = false;
				break;
			case Sys.UI.Key.down:
				this._changeHighlight(e.keyCode);
				bubble = false;
				break;			
			default:
				this._getSuggestions();
		}
		
		return bubble;
	},
	
	_getSuggestions: function(){		
		this.set_inputLength(this.get_element().value.trim().length);
		
		//Check if something was typed in and clear it out
		if (this.get_element().value.trim() === ""){
			this.set_localMatches(this._cache);
			this.RemoveSuggestions();
			this._updateHelp(this.get_helpMsg());
			this.ShowHelp();
			return false;
		}
		
		//Do the search
		var escapedSearch = this._escapeRegEx(this.get_element().value.trim()); //clean up the search
		this.set_localMatches(this._doSearch(escapedSearch, this.get_displayLimit()));
		
		//Create the list of something was returned
		if (this.get_localMatches().length > 0){
			this.get_localMatches().sort(this._compareA1Handler);
		}		
		this._createList(this.get_localMatches());
		
		return false;
	},
	
	_doSearch: function(searchTerm, resultsLimit){
		//Replaces spaces and non characters to better search terms
		var c;
		for(var x=0; x<searchTerm.length; x++){
			c = searchTerm.charCodeAt(x);
			if (c == 32) 
				searchTerm = searchTerm.substr(0, x) + "\\s" + searchTerm.substr(x+1);
			if (c > 127) 
				searchTerm = searchTerm.substr(0, x) + "\\u" + c.toString(16) + searchTerm.substr(x+1);
			
		}
		
		//Does the regex checking/matching
		var re = new RegExp("^" + searchTerm, "i");
		var matched = [];
		matched.TotalMatches = 0;
		Array.forEach(this._cache, this._findMatch, {"matched":matched,"regex":re,"resultsLimit":resultsLimit});
		  
		return matched;	
	},
	
	_findMatch: function(element, index, array){
		var match = false;
		  
		if (element.get_a1()){
			if (this.regex.test(element.get_a1())){
				match = true;
			}
		}
			
		if (element.get_a2()){ 
			if (this.regex.test(element.get_a2())){
				match = true;
			}		
		}
	  
	  
		if (match) {	
			if (this.matched.length < this.resultsLimit) {
				this.matched.push(element);
			}
			this.matched.TotalMatches++;
		}
	},
	
	_createList: function(arr){			
		//Reset for new list
		if (this._helpDiv) 
			this._helpDiv.parentNode.removeChild(this._helpDiv);
			
		//Remove the list
		this.RemoveSuggestions();
		
		//Setup for browse mode to show some items at initialization
		if (this.get_browseMode()){			
			this._visibleItems = 10; // I made this up!
			this._startVis = 0;
			this._endVis = this._startVis + this._visibleItems;
		}

		//Wrapper div setup
		var wrapperDiv = document.createElement("div");
		wrapperDiv.id = this._idAs;
		wrapperDiv.className = this.get_wrapperDivClass();	
	
		//Scrolling div setup
		var div = document.createElement("div");
		div.id = this._idAs + "_scroll";
		div.className = this.get_className();
		
		//The list itself
		var ul = document.createElement("ul");
		ul.id = "as_ul";
		
		//Determing how many items to show in list
		var limit;		
		if (this.get_browseMode()){ //Browse mode settings
			if(arr.length > this._visibleItems) //More array items than we're supposed to show
				limit = this._visibleItems;
			else //Not enough items to show
				limit = arr.length;
		}
		else if (arr.length > this.get_displayLimit()) //Too many items to show
			limit = this.get_displayLimit();
		else 
			limit = arr.length;
		
		
		//This is the meat of the method where the list is parsed for highlighting while typing
		for (var i=0;i<limit;i++){
			var friend = arr[i];
		
			this._renderFriendResult(friend, i);
			
			//Add friend to the list
			ul.appendChild( friend.get_element() );
		}
		
		//Adds an empty LI just to show there is a longer list for browsing
		if (this.get_browseMode() && (arr.length > this._visibleItems || this._totalFriendCount > this._visibleItems)){
			
			var arrLength;
			if (this._totalFriendCount === 0)
				arrLength = arr.length;
			else{
				arrLength = this._totalFriendCount;
								
				//finish loading friends list
				if (this._totalFriendCount > this._processedFriendCount)
					window.setTimeout(Function.createDelegate(this, this._finishFriendsProcessing), 0);
			}
		}
			
		
		if(this.get_browseMode() && arr.length > this._visibleItems){
			
			//Make list taller without adding extra elements
			/*var listHeight = arrLength * this._singleItemHeight;
			ul.style.height = listHeight + "px";*/
			
			for (var x=limit;x<arrLength;x++){
				
				var li = document.createElement("li");
				li.id = "item" + x;
				li.style.height = this._singleItemHeight + "px";
				li.innerHTML = "&nbsp;";
					
				ul.appendChild(li);		
				
				this._localRendered[x] = 0;
			}
			
		}
		
		div.appendChild(ul);
		wrapperDiv.appendChild(div);
			
		this._scrollDiv = div;	
		
		this.set_suggestionsCount(arr.length);
		
		// no results
		//
		// We're going to drop out here.
		if (arr.length === 0 && this.get_showNoResults()){
			var noResultsDiv = document.createElement("div");
			noResultsDiv.id = "helpDiv";
			noResultsDiv.className = "fullHelp";
			noResultsDiv.innerHTML = MySpaceRes.AddressBooks.NoMatchesFound;
			
			var pos = Sys.UI.DomElement.getLocation(this.get_element());
			if (browser.isMozilla || browser.isGecko)
			{
				noResultsDiv.style.width = (this.get_element().offsetWidth - 4) + "px";
				noResultsDiv.style.left = (pos.x -1) + "px";
				noResultsDiv.style.top 		= ( pos.y + this.get_element().offsetHeight + this.get_offsety() + 5) + "px";
			}
			else
			{
				noResultsDiv.style.width = (this.get_element().offsetWidth + 2) + "px";
				noResultsDiv.style.left = (pos.x+1) + "px";
				noResultsDiv.style.top 		= ( pos.y + this.get_element().offsetHeight + this.get_offsety() + 7) + "px";
			}
			document.getElementsByTagName("body")[0].appendChild(noResultsDiv);
			this.ResetHelpTimeout();			
			this.set_suggestionsCount(0);
			return;
		}
		
		if (arr.length === 0){
			this.ResetHelpTimeout();			
			return;
		}
		
		//Show footer
		if (this.get_displayFooter()){
			if (this.get_displaySort()){
				var sortDivContent;	
				if (sortOrder == 0)
					sortDivContent = "<div class=\"clear\">" + MySpaceRes.AddressBooks.SortBy + ":<br><dl class=\"sortBox\"><dt><input type=\"radio\" name=\"sortCol\" value=\"0\" onClick=\"changeSort(this.value);\" CHECKED><label>"+MySpaceRes.AddressBooks.DisplayName+"</label></dt><dt><input name=\"sortCol\" value=\"1\" onClick=\"changeSort(this.value);\" type=\"radio\"><label>"+MySpaceRes.AddressBooks.UsernameLower+"</label></dt></dl></div>";
				else
					sortDivContent = "<div class=\"clear\">" + MySpaceRes.AddressBooks.SortBy + ":<br><dl class=\"sortBox\"><dt><input type=\"radio\" name=\"sortCol\" value=\"0\" onClick=\"changeSort(this.value);\"><label>"+MySpaceRes.AddressBooks.DisplayName+"</label></dt><dt><input type=\"radio\" name=\"sortCol\" value=\"1\" onClick=\"changeSort(this.value);\" CHECKED><label>"+MySpaceRes.AddressBooks.UsernameLower+"</label></dt></dl></div>";
				var sortDiv = MySpace.Common.FriendSuggest.CreateElement("div", {id:"sortDiv", className:"as_warning_sort"}, sortDivContent, true);
			}
			
			if 	(arr.length < this._cache.length){
				var floatWrapperDiv = MySpace.Common.FriendSuggest.CreateElement(  "div", {className:"as_warning_wrapper"}, "", false);
				var moreDiv = MySpace.Common.FriendSuggest.CreateElement(  "div", {className:"as_warning_sm_left"}, "<table><tr><td class=\"push\">" + MySpaceRes.AddressBooks.ShowingXOfYOfMatchedResults.replace(/\{0\}/gi, arr.length).replace(/\{1\}/gi, this._cache.length) + "<br><label class=\"orange\">"+MySpaceRes.AddressBooks.KeepTypingToNarrowResults+"</label></td></tr></table>", true); //<td class=\"sortBy\" onClick=\"showSort();\">Sort by&nbsp;</td>
				
				floatWrapperDiv.appendChild(moreDiv);
				if (this.get_displaySort()) floatWrapperDiv.appendChild(sortDiv);
				wrapperDiv.appendChild(floatWrapperDiv);
			}
			else{
				var floatWrapperDiv = MySpace.Common.FriendSuggest.CreateElement(  "div", {className:"as_warning_wrapper"}, "", false);
				var showingAllDiv = MySpace.Common.FriendSuggest.CreateElement(  "div", {className:"as_warning_sm_left"}, "<table><tr><td class=\"push\">"+MySpaceRes.AddressBooks.ShowingAllMatchedResults+"<br><label class=\"orange\">"+MySpaceRes.AddressBooks.KeepTypingToNarrowResults+"</label></td></tr></table>", true);
				
				floatWrapperDiv.appendChild(showingAllDiv);
				if (this.get_displaySort()) floatWrapperDiv.appendChild(sortDiv);
				wrapperDiv.appendChild(floatWrapperDiv);
			}
	
		}
		this._layout(wrapperDiv);
		
		//Add the wrapper to the specified place in the DOM
		if (this.get_ownerDiv().id !== "body")
			this.get_ownerDiv().appendChild(wrapperDiv);
		else //or the body
			document.getElementsByTagName("body")[0].appendChild(wrapperDiv);
		
		//Resize option
		if (this.get_resize()){
			if (ul.childNodes.length > 0)
			{
				this.singleHeight = ul.childNodes[0].offsetHeight;
				
				if (this.get_browseMode() && arr.length>this._visibleItems) {
					var renderHeight = this.singleHeight * (arr.length-limit);
					
					var innerHeight=0;
					for (var x=0;x<limit-1;x++)
					{
						innerHeight += ul.childNodes[x].offsetHeight;
					}
					
					div.style.height = innerHeight + "px";
				}
			}
		}
		
		$addHandlers(div, {scroll:this._trackBrowseMode}, this);
		this._highlightIndex = 0;
		
		ul.parentNode.style.position = "relative";
	},
	
	_setSuggestionsLocal : function (jsondata){
		
		var jsonDataLength = jsondata.length;
		if (jsonDataLength > 0){
			this._startTimer();
			
			var limit = 10;
			this._totalFriendCount = jsonDataLength;
			
			//Need to compensate for a shorter array of friends, under the limit
			if (jsonDataLength < limit){
				limit = jsonDataLength;
			}
			else if (this.get_clientCachedFriends().length > 0){ //For the regular load to process them all
				limit = this.get_clientCachedFriends().length;
			}
			
			if (this._cache === null)
				this._cache = new Array(this._totalFriendCount);
			if (this._localMatches === null)
				this._localMatches = new Array(this._totalFriendCount);
			
			
			for (var i=0;i<limit;i++){				
				//CREATE THE FRIEND OBJECT
				var friend = this._createFriend(jsondata[i], i);	
			}				
			
			if (jsonDataLength > limit){
				this._totalFriendCount = jsonDataLength;
			}
			else if (jsonDataLength <= limit){
				this._raiseEvent("friendsLoaded");
				this._endTimer(String.format("Added {0} friends locally", limit));	
			}

			//Save the rest for later processing
			this._unprocessedFriends = jsondata;
		}
	},
	
	_createFriend: function(item, itemIndex){
		var strA1 = this.get_a1Field();
		var strA2 = this.get_a2Field();
		
		var li = document.createElement("li");
				
		/*
		var friendProps = {"ID":item.UserId,
							"a1":eval("item." + strA1),
							"a2":eval("item." + strA2),
							"imgURI":item.ImageUri};
							
		var friendEvents = {"propertyChanged":highlightWatcherHandler,
							 "propertyChanged":clickedFriendHandler};
					
		
		//Setting properties manually to help with load times
		var friend =  $create(MySpace.Common.Friend, friendProps, friendEvents, null, li);
		*/
		
		//Truncated $create statement
		
		var element = li;
		var friend = new MySpace.Common.Friend(element);
		var app = Sys.Application;
		
		app._createdComponents[app._createdComponents.length] = friend;		
		
		//Properties
		friend.set_ID(item.UserId);
		if (strA1 !== null) 
			friend.set_a1(eval("item." + strA1));
		if (strA2 !== null) 
			friend.set_a2(eval("item." + strA2));
		friend.set_imgURI(item.ImageUri);		
		
		//Events
		friend.add_propertyChanged(this._highlightWatcherHandler);
		friend.add_propertyChanged(this._clickedFriendHandler);		
		friend.initialize();		
		
		//Store each friend in cached array
		this._cache[itemIndex] = friend;	
		this.get_localMatches()[itemIndex] = friend;

		li.id = "item" + itemIndex;		
		
		//Is this needed now that it's a property on each friend object?
		this._localRendered[itemIndex] = 0;
		++this._processedFriendCount;
		
		return friend;
	},
	
	_createFriendsBatch: function(friendsData){
		var batchLength = friendsData.length;
		for (var k=0;k<batchLength;k++){
			var friend = this._createFriend(friendsData[k]);
		}
	},
	
	_finishFriendsProcessing: function(){
		
		var batchhandler = Function.createDelegate(this, this._createFriendsBatch);
		startRow = 10;
		limit = this._unprocessedFriends.length;
		
		for (var j=startRow; j<limit; j++){
			this._createFriend(this._unprocessedFriends[j], j);
		}
		
		/*
		//Batch up 10 at a time using
		//for every 10 items, kick off a window.setTimeout(0);
		var tenFriends = [];
		var countToTen = 0;
		for (var i = 0; i < limit; i++){
			if (countToTen < 10){
				Array.add(tenFriends, this._unprocessedFriends[i]);	
				countToTen++;
			}

			//Update captions because we are at capacity or we're at the end of the list
			if (countToTen === 10 || i === (limit - 1)){
				this._createFriendsBatch(tenFriends);
				
				countToTen = 0;
				Array.clear(tenFriends);
			}
		}		
		*/
		
		this._endTimer(String.format("Added {0} friends more", limit));		
				
		this._raiseEvent("friendsLoaded");
	},
	
	_highlightWatcher: function(sender, e){
		if(e.get_propertyName() === '_highlighted'){
			if(sender.get_highlighted()){			
				
				//Clear old highlight
				if(this._clearHighlight()){
					Array.add(this._highlightedFriends, sender);		

					//set again in case the event was a mouse over which doesn't increment highlightIndex
					this._highlightIndex = sender.get_listIndex();
					
				}
			}
		}
	},
	
	_addItemToList: function(friend, pos, itemIndex){
	
		if (itemIndex >= this.get_localMatches().length) return;
		var ul = $get("as_ul");
		// removing options for speed
				
		this._renderFriendResult(friend, itemIndex);
		
		if (pos === "top") 
			ul.insertBefore(friend.get_element(), ul.firstChild);
		else if (pos === "bottom")
			ul.appendChild(friend.get_element());
		else
			ul.insertBefore(friend.get_element(), ul.childNodes[itemIndex]);
			
		if (ul.childNodes.length > (itemIndex+1))
			ul.removeChild(ul.childNodes[itemIndex+1]);
	},
	
	_renderFriendResult: function(friend, itemIndex){
		//have the friend render it's UI to show			
		friend.Render();
		this._localRendered[itemIndex] = 1;
		friend.set_listIndex(itemIndex+1);
		
		var searchFld1 = friend.get_a1();
		var searchFld2 = friend.get_a2();	
		
		var partialMatch = searchFld1.toLowerCase().indexOf(this.get_element().value.trim().toLowerCase());
		var span = friend.get_element().getElementsByTagName("span")[0];
		
		span.innerHTML = "";
		if (partialMatch > -1){
			//Clear out the original span
			span.className = "";
			
			//Add highlight span
			var highlightSpan = document.createElement("span");
			highlightSpan.className = "highlight";
			highlightSpan.innerHTML = searchFld1.substring(partialMatch, partialMatch+this.get_element().value.trim().length);
			
			//Add bold span
			var boldSpan = document.createElement("span");
			boldSpan.className = "acFirst";
			boldSpan.innerText = searchFld1.substring(partialMatch+this.get_element().value.trim().length);
			boldSpan.textContent = searchFld1.substring(partialMatch+this.get_element().value.trim().length);
			span.appendChild(highlightSpan);
			span.appendChild(boldSpan);
		}
		else{
			var boldSpan = document.createElement("span");
			boldSpan.className = "acFirst";
			boldSpan.innerHTML = friend.get_originalDisplay();
			
			span.appendChild(boldSpan);
		}
		
		//2nd search field highlight
		if (searchFld2 != null){
			partialMatch2 = searchFld2.toLowerCase().indexOf(this.get_element().value.toLowerCase());		
			var smallSpan1 = document.createElement("span");
			smallSpan1.className = "smallUserName";					
				
			if (partialMatch2==0){
				
				var smallSpan2 = document.createElement("span");
				var smallSpan3 = document.createElement("span");
				
				smallSpan1.innerHTML = " (" + searchFld2.substring(0,partialMatch2);
				
				smallSpan2.className = "highlight";
				smallSpan2.innerHTML = searchFld2.substring(partialMatch2, partialMatch2+this.get_inputLength());
				
				smallSpan3.className = "smallUserName";
				smallSpan3.innerHTML = searchFld2.substring(partialMatch2+this.get_inputLength()) + ")";
				
				//Add to DOM
				span.appendChild(smallSpan1);
				span.appendChild(smallSpan2);
				span.appendChild(smallSpan3);	
			}
			else{
				smallSpan1.innerHTML = " (" + searchFld2 + ")";

				//Add to DOM
				span.appendChild(smallSpan1);	
			}				
			
		}
	},
		
	_drawInContents: function(){
		var slide = this._scrollDiv.scrollTop;
		
		var ul = $get("as_ul");
		
		// draw in all items covered by last scroll - selectively turning on divs
		var childNodesLength = ul.childNodes.length;
		for (var y = 0; y<childNodesLength;y++){			
			if (ul.childNodes[y].offsetTop > slide) break;
		}
			
		for (var x = y-4;x<y+this._visibleItems+4;x++){		
			if (this._localRendered[x] === 0) 
				this._addItemToList(this.get_localMatches()[x], "mid", x);
		}
	},
	
	_trackBrowseMode: function(e){
		this._drawInContents();
	},
	
	_changeHighlight : function(key){	
		var list = $get("as_ul");
		if (!list)
			return false;
		
		var n;
	
		if (key === Sys.UI.Key.up){
			n = this._highlightIndex - 1;
		}
		else if (key === Sys.UI.Key.down){
			n = this._highlightIndex + 1;
		}
		
		
		if (n > list.childNodes.length)
			n = list.childNodes.length;
		if (n < 1)
			n = 1;
			 
		var innerHeight=0;
		for (var x=this._shifted;x<n;x++){
			innerHeight += list.childNodes[x].offsetHeight - 2
		}
		
		if (n === 1)
			this._scrollDiv.scrollTop = 0;		
		else if (n === list.childNodes.length)
			this._scrollDiv.scrollTop = innerHeight;
		else if (innerHeight < (this._scrollDiv.scrollTop + list.childNodes[n].offsetHeight) || innerHeight > this._scrollDiv.clientHeight + this._scrollDiv.scrollTop){
			if (n >= this._highlightIndex) { // going down
				this._scrollDiv.scrollTop += list.childNodes[n].offsetHeight + 2;
			} else {// goin up
				this._scrollDiv.scrollTop -= list.childNodes[n].offsetHeight - 4;
			}
		}			
		this._setHighlight(n);
	},
	
	_setHighlight: function(n){
		var list = $get("as_ul");
		if (!list)
			return false;
		
		this._highlightIndex = parseInt(n);
		
		//Get Friend to highlight
		var friend = this.get_localMatches()[this._highlightIndex-1];
		
		//Highlight the friend
		friend.get_highlightHandler()(true);
		
		//Is this needed?
		this.KillTimeout();
	},
	
	_clearHighlight: function(){
		var list = $("as_ul");
		if (!list)
			return false;
		
		var hightlightedFriendsLength = this._highlightedFriends.length;
		for (var i=0;i<hightlightedFriendsLength;i++){
			//Unhighlight
			this._highlightedFriends[i].get_highlightHandler()(false);
		}
		Array.clear(this._highlightedFriends);
		
		return true;
	},
	
	_clickedFriend: function(sender, e){
		if(e.get_propertyName() === '_clicked'){
			if(sender.get_clicked()){		
				/*if (this.get_localMatches().length === 1)
					this._highlightIndex = 1;*/
				
				this.ClearSuggestions();
				
				
				if (typeof(this.get_callback()) === "string") //Check to make sure the user set a valid callback function
				{
					//Not implemented yet
					
					if (this.get_displayRecentList()) 
					{
						this.AddToRecentCache(sender);	
					}
					
					eval(this.get_callback())(sender);//Call callback
					
				}
				else{
					var err = Error.argumentNull("_callback");
					throw err;
				}
				
				this.get_element().value = sender.get_a1(); //Set textbox value to the displayname				
			}
		}
	},
	
	HideAll: function(e){
		var targ;
		if (!e) var e = window.event;
		if (e.target) targ = e.target;
		else if (e.srcElement) targ = e.srcElement;
		if (targ.nodeType == 3) // defeat Safari bug
			targ = targ.parentNode;
		if (targ.tagName == 'INPUT') {
			if (targ.id.indexOf("_to_to") > -1) {
				this.killTimeout();
				return false;
			}
		}
		this.ResetTimeout();
	},
	
	KillTimeout: function(){
		clearTimeout(this._hideTimeout);
	},

	ResetTimeout: function(){
	
		clearTimeout(this._hideTimeout);	
	
		if (!this.get_browseMode()) 
			this._hideTimeout = setTimeout(this.get_clearSuggestionsHandler(), 1000);
	},
	
	KillHelpTimeout: function(){
		clearTimeout(this.helpTimeout);
	},
	
	ResetHelpTimeout: function(){
		clearTimeout(this.helpTimeout);
		
		var clearHelpHandler = Function.createDelegate(this, this.ClearHelp);
		this.helpTimeout = setTimeout(clearHelpHandler, 2500);
	},
	
	ClearHelp : function (){
		this.KillHelpTimeout();
		
		var el = this._helpDiv;
		if (el !== null && el.parentNode !== null) 
			var helpFade = new _MySpace.Fader(el,1,0,250,function () { el.remove(); });
	},
	
	ClearSuggestions : function (){
		this.KillTimeout();
		
		if (this._helpDiv)
			Effect.Fade(this._helpDiv);
	},
	
	RemoveSuggestions: function(){
		this.KillTimeout();
		
		if (typeof(this._idAs) !== "undefined"){
			theNode = $get(this._idAs);
			
			if(typeof(theNode) !== "undefined" && theNode !== null){
				parentNode = $get(this._idAs).parentNode;
				parentNode.removeChild(theNode);
			}
		}
	},

	_updateHelp: function(msg){
		if (this._helpDiv){
			this.ResetHelpTimeout();
			this._helpDiv.innerHTML = msg;
		}
	},
	
		
	
	//SORTING	
	ReSort: function(){
		this.ChangeSort(this._sortOrder);
	},
	
	ChangeSort: function(sortCol){
		
		if (sortCol === 1) 
			this.get_localMatches().sort(CompareA2);
		else
			this.get_localMatches().sort(this._compareA1); 
		this._sortOrder = sortCol;		
		
		this._createList(this.get_localMatches());
		
		return true;
	},
	
	_compareA1: function(a, b){
		return (this._stringCompare(a.get_a1().toLowerCase(),b.get_a1().toLowerCase()));
	},
	
	_compareA2: function(a, b){
		return (this._stringCompare(a.get_a2().toLowerCase(),b.get_a2().toLowerCase()));
	},
	
	_isWhiteSpace: function(x){
		return (x.charCodeAt(0) <= 32) ? true : false;
	},
	
	_isNumeric: function(x){
		var code = x.charCodeAt(0);
		return (code >= 48 && code <= 57) ? true : false;
	},
	
	_stringCompare: function (x,y){
		
		var ix = 0, iy = 0; 
		var zx = 0, zy = 0;
		var cx, cy, out;
		
		while (true){
			// count naughts
			zx = zy = 0;
			
			cx = x.charAt(ix);
			cy = y.charAt(iy);
			
			// skip spaces / naughts
			while (this._isWhiteSpace(cx) || cx == "0") {
				if (cx == "0")
					zx++;
				else
					zx = 0;
				cx = x.charAt(++ix);
			}
			while (this._isWhiteSpace(cy) || cy == "0") {
				if (cy == "0")
					zy++;
				else 
					zy = 0;
				cy = y.charAt(++iy);
			}
			
			if (this._isNumeric(cx) && this._isNumeric(cy)) {
				if ((out = this._digitalCompare(x.substring(ix), y.substring(iy))) != 0) return out;
			}
			
			if (cx == 0 && cy == 0) return zx - zy;
			if (cx < cy)
				return -1;
			else if (cx > cy)
				return 1;
			
			++ix, ++iy;       
		}
	},
	
	_digitalCompare: function(x,y){
		var offset = 0, ix = 0, iy = 0;
		var cx, cy;
		
		for (;; ix++, iy++) {
			cx = x.charAt(ix);
			cy = y.charAt(iy);
			
			if (!this._isNumeric(cx) && !this._isNumeric(cy)) {
				return offset;
			} else if (!this._isNumeric(cx)) {
				return -1;
			} else if (!this._isNumeric(cy)) {
				return 1;
			} else if (cx < cy) {
				if (offset == 0) offset = -1;
			} else if (cx > cy) {
				if (offset == 0) offset = 1;
			}
		}
	},
	
	_startTimer: function(){
		this._startms = new Date().getTime();
	},
	
	_endTimer: function(msg){
		endms = new Date().getTime();
		var executionTime = endms - this._startms;
		/*if (this.get_debug())
			Sys.Debug.trace(msg + " : " + executionTime + " ms");*/
	},
	
	_escapeRegEx: function(s){ 
		return s.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1') 
	}
	
	
	
	//dispose:

}
MySpace.Common.FriendSuggest.registerClass('MySpace.Common.FriendSuggest', Sys.UI.Control);

MySpace.Common.FriendSuggest.CreateElement = function ( type, attr, cont, html ){
	var ne = document.createElement( type );
	if (!ne)
		return false;
		
	for (var a in attr)
		ne[a] = attr[a];
		
	if (typeof(cont) == "string" && !html)
		ne.appendChild( document.createTextNode(cont) );
	else if (typeof(cont) == "string" && html)
		ne.innerHTML = cont;
	else if (typeof(cont) == "object")
		ne.appendChild( cont );

	return ne;
}
MySpace.Common.FriendSuggest.Imgerr = function(imgObj) {
	imgObj.src = "../img/no_pic.gif";
}

MySpace.Common.Friend = function(element){
    MySpace.Common.Friend.initializeBase(this, [element]);
}
MySpace.Common.Friend.prototype = {

	_ID: null,
	_a1: null,
	_a2: null,
	_imgURI: null,
	_callback: null,
	_originalDisplay: null,
	_displayNameSpan: null,
	_rendered: false,
	_highlighted: false,
	_highlightHandler: null,
	_clicked: null,
	_listIndex: null,
	
	get_ID: function(){
		return this._ID;
	},
	set_ID: function(value){
		this._ID = value;
	},
	
	get_a1: function(){
		return this._a1;
	},
	set_a1: function(value){
		this._a1 = value;
	},
	
	get_a2: function(){
		return this._a2;
	},
	set_a2: function(value){
		this._a2 = value;
	},
	
	get_imgURI: function(){
		return this._imgURI;
	},
	set_imgURI: function(value){
		this._imgURI = value;
	},
	
	get_callback: function(){
		return this._callback;
	},
	set_callback: function(value){
		this._callback = value;
	},
	
	get_originalDisplay: function(){
		return this._originalDisplay;
	},
	set_originalDisplay: function(value){
		this._originalDisplay = value;
	},
	
	get_displayNameSpan: function(){
		if (typeof(this._displayNameSpan) !== "string")
			return this._displayNameSpan;
		else{
			this._displayNameSpan = $get(this._displayNameSpan);
			return this._displayNameSpan;
			
		}
	},
	set_displayNameSpan: function(value){
		this._displayNameSpan = value;
	},
	
	get_rendered: function(){
		return this._rendered;
	},
	set_rendered: function(value){
		this._rendered = value;
	},
	
	get_highlighted: function(){
		return this._highlighted;
	},
	set_highlighted: function(value){
	
		if (this._highlighted !== value){
			this._highlighted = value;
			
			this.raisePropertyChanged("_highlighted");
		}
	},
	
	get_highlightHandler: function(){
		return this._highlightHandler;
	},
	set_highlightHandler: function(value){
		this._highlightHandler = value;
	},
		
	get_clicked: function(){
		return this._clicked;
	},
	set_clicked: function(value){
		if (this._clicked !== value){
			this._clicked = value;		
			
			this.raisePropertyChanged("_clicked");
		}
	},	
	
	get_listIndex: function(){
		return this._listIndex;
	},
	set_listIndex: function(value){
		this._listIndex = value;
	},
	
	initialize: function(){
	
		//Setup delegates
		this.set_highlightHandler(Function.createDelegate(this, this.Highlight));
	},
	
	Render: function(){
		if(!this.get_rendered()){
			if (this.get_element().innerHTML !== ""){
				this.get_element().innerHTML = "";
				
			}
		
			//Make elements for the friend object
			var anchorWrapper = document.createElement("a");
			var img = document.createElement("img");
			var spanDisplayName = document.createElement("span");
			
			anchorWrapper.href ="#";
			
			img.name = img.id = "uimg" + this.get_ID();
			img.src = this.get_imgURI();
			img.style.width = 20 + "px";
			img.style.height = 20 + "px";
			$addHandlers(img, {error: this._imgerr}, this) 
			
			spanDisplayName.id = "display" + this.get_ID();
			spanDisplayName.className = "acFirst";
			spanDisplayName.innerHTML = this.get_a1();
			this.set_originalDisplay(this.get_a1());
			
			//Optional
			//var spanUserName = document.createElement("span");
			
			//Add all the elements together
			anchorWrapper.appendChild(img);
			anchorWrapper.appendChild(spanDisplayName);
			this.get_element().appendChild(anchorWrapper);
			
			//Set for later use
			this.set_displayNameSpan(spanDisplayName.id);
			
			//Add events to the list item
			$addHandlers(this.get_element(), {'mouseover':this.Highlight, 'mouseout': this.Highlight, click: this._clickedFriend}, this);
			
			this.set_rendered(true);
		}
	},
	
	Highlight: function(showHighlight){	
		if (typeof(showHighlight) === "undefined")
			showHighlight = false;
	
		if (!Sys.UI.DomElement.containsCssClass(this.get_element(), "as_highlight") && showHighlight) {			
			this.set_highlighted(true);
			Sys.UI.DomElement.addCssClass(this.get_element(), "as_highlight");
			this.get_displayNameSpan().style.fontWeight = "bold";
		}
		else{
			Sys.UI.DomElement.removeCssClass(this.get_element(), "as_highlight");
			this.get_displayNameSpan().style.fontWeight = "normal";
			this._highlighted = false;		
			this._clicked = false;
		}
	},
	_clickedFriend: function(){
		this.set_clicked(true);
	},
	
	_imgerr: function(e) {
		e.target.src = "../img/no_pic.gif";
	},

	dispose: function(){
		_userID = null;
		_a1 = null;
		_a2 = null;
		_img = null;
		_callback = null;
		
		this.set_highlightHandler(null);
	}
}
MySpace.Common.Friend.registerClass('MySpace.Common.Friend', Sys.UI.Behavior);

