function ParseSearchTokens(txtbox,hidfld)
{

    //var searchButton = document.getElementById[button];
	var userSearch = txtbox.value;	
	//var userSearch = searchButton.value;
	//alert(userSearch)
	var searchType;
	
	// Create the UserQuery object
	var uq = new UserQuery(); 
	var isOK = uq.ParseTokens(userSearch); 
	//alert(userSearch);
	//alert('isOK :' + isOK);
	if (isOK) 
	{ 
		isOK=uq.Validate(); 
		if (isOK) 
		{ 
			sqlSearchStr = uq.GetMSSQLSearchStr();
			userSearch = '1,' + userSearch;
			//alert('Successful');
			//document.all['Searchnews1$hdnSearchkeyword'].value = userSearch;
			hidfld.value=userSearch;
			//alert('finished');
		}
		else
		{
			//alert('Failure');
			userSearch = '0,' + userSearch;
			hidfld.value = userSearch;
		}
		
	}
	else
		{
			//alert('Failure');
			userSearch = '0,' + userSearch;
			hidfld.value = userSearch;
		}
	//alert(userSearch);
	//alert('End of Parsing Tokens');
	
	
	//alert(document.all['TextBox1'].value);
	//WebForm_DoCallback('__Page',userSearch,ShowUserResultFromServer,"",null,false); 
	
	
}

function ShowUserResultFromServer(arg, context) 
{
	Message.innerText = arg;
}
 
 
function UserQuery_InsertDefaultOperator(token)
{
	//alert('UserQuery_InsertDefaultOperator : token = ' +token);
	this.tokens[this.tokens.length] = this.builtIn("and");
}


function UserQuery_GetMSSQLSearchStr()
{	
	//alert('UserQuery_GetMSSQLSearchStr');
	
	var searchStr = this.tokens[0].value;
	//alert('searchStr' + searchStr);
	
	for (var i=1;i<this.tokens.length;i++)
	{
		searchStr += " " + this.tokens[i].value;
	}
	
	return searchStr;
}


function UserQuery_ClassInitialize()
{
	//alert('UserQuery_ClassInitialize()');
	if (!UserQuery.ClassInit)
	{
		UserQuery.ClassInit = true;
		
		UserQuery.USERITEM = 1;
		UserQuery.ANDOP = 2;
		UserQuery.OROP = 4;
		UserQuery.NOTOP = 8;
		UserQuery.LEFTPAREN = 16;
		UserQuery.RIGHTPAREN = 32;
		UserQuery.NEAROP = 64;
		UserQuery.NOISEWORD = 128;

		// Derived logical types (for comparison only)
		UserQuery.OPERATOR = UserQuery.ANDOP|UserQuery.OROP|UserQuery.NOTOP|UserQuery.NEAROP;
		UserQuery.BINARYOP = UserQuery.ANDOP|UserQuery.OROP|UserQuery.NEAROP;
		UserQuery.EXPRESSION = UserQuery.RIGHTPAREN|UserQuery.USERITEM;
	}
	
}


function UserQuery()
{
	//alert('UserQuery()');
	UserQuery_ClassInitialize();
	
    //alert('hiw');
    
	this.tokens = new Array();
	this.builtIn = new ActiveXObject("Scripting.Dictionary");
	//alert("UserQuery:this.builtIn" + this.builtIn);
	this.error = "";
	this.InsertDefaultOperator = UserQuery_InsertDefaultOperator;
	this.ParseTokens = UserQuery_ParseTokens;
	this.AddToken = UserQuery_AddToken;
	this.AddBuiltIn = UserQuery_AddBuiltIn;
	this.GetToken = UserQuery_GetToken;
	this.Validate = UserQuery_Validate;
	this.GetMSSQLSearchStr = UserQuery_GetMSSQLSearchStr;
	this.UnrollExpression = UserQuery_UnrollExpression;
	this.GetLastToken = UserQuery_GetLastToken;
	
	this.AddBuiltIn("and","AND",UserQuery.ANDOP);
	this.AddBuiltIn("or","OR",UserQuery.OROP);	
	this.AddBuiltIn("near","NEAR",UserQuery.NEAROP);	
	this.AddBuiltIn("not","NOT",UserQuery.NOTOP);	
	this.AddBuiltIn("(","(",UserQuery.LEFTPAREN);	
	this.AddBuiltIn(")",")",UserQuery.RIGHTPAREN);
	
	return this;
}

function UserQuery_AddToken(token)
{
	this.tokens[this.tokens.length] = token;
}

function UserQuery_GetLastToken()
{
	var lastToken = null;
	
	if (this.tokens.length > 0)
		lastToken = this.tokens[this.tokens.length-1];
	
	return lastToken;
}

// Attempts to validate for the following grammar
// Expression : USERITEM | USERITEM OROP Expression | UNARYOP USERITEM
function UserQuery_Validate()
{
	var valid = true;
	var lastItemOK = false;
	var nextItem = UserQuery.USERITEM | UserQuery.LEFTPAREN | UserQuery.NOTOP;
	var balance = 0;
	
	if (this.tokens.length == 0)
	{
		valid = false;
		this.error = "Empty search string, probably because all input words were noise words ('a','the', etc.).";
	}
	else
		{
		for (var tokIndex=0; tokIndex < this.tokens.length;tokIndex++)
		{
			if ((this.tokens[tokIndex].type & nextItem) != 0)
			{
				switch (this.tokens[tokIndex].type)
				{
					case (UserQuery.USERITEM):
						nextItem = UserQuery.BINARYOP |UserQuery.RIGHTPAREN;
						lastItemOK = true;
						break;
					case (UserQuery.ANDOP):
						nextItem = UserQuery.USERITEM | UserQuery.NOTOP | UserQuery.LEFTPAREN;
						lastItemOK = false;
						break;
					case (UserQuery.NEAROP):
						nextItem = UserQuery.USERITEM;
						lastItemOK = false;
					case (UserQuery.OROP):
						nextItem = UserQuery.USERITEM | UserQuery.LEFTPAREN;
						lastItemOK = false;
						break;
					case (UserQuery.NOTOP):
						nextItem = UserQuery.USERITEM | UserQuery.LEFTPAREN;
						lastItemOK = false;
						break;
					case (UserQuery.LEFTPAREN):
						balance++;
						nextItem = UserQuery.USERITEM;
						lastItemOK = false;
						break;
					case (UserQuery.RIGHTPAREN):
						balance--;
						nextItem = UserQuery.OROP | UserQuery.ANDOP;
						if (balance > 0)
							lastItemOK = false;
						else
							lastItemOK = true;
						break;
				}
				
				if (balance < 0)
				{
					valid = false;
					this.error = "Mismatched parenthesis";
					//alert('balance<0');
					break;
				}
			}
			else
			{
			    //alert('Else');
				valid = false;
				this.error = "Unexpected word or character found: " + this.tokens[tokIndex].value;
				break;
			}
				
		}
	
		if (balance != 0)
		{
			valid = false;
			this.error = "Mismatched parenthesis";
//			alert('balance != 0');
		}
		else if (valid && !lastItemOK)
		{
//		    alert('valid && !lastItemOK');
			valid = false;
			this.error = "Unexpected end of search string after: " + this.tokens[this.tokens.length-1].value;
	
		}
	}
//	alert('Valid:' + valid);
	return valid;
}

// This function searches back until it reaches the first uType token truncating any
// tokens that follow it
function UserQuery_UnrollExpression(uType)
{
	var newLength = this.tokens.length;
	
	for (var i=this.tokens.length; i > 0 ; i--)
	{
		if ( (this.tokens[i-1].type & uType) != 0)
		{
			newLength = i-1;
		}
		else
			break;
		
	}

	this.tokens.length = newLength;
}

function UserQuery_AddBuiltIn(key,value,type)
{
	var token = new Object();
	token.type = type;
	token.value = value;
	this.builtIn.Add(key,token);
}

function UserQuery_ParseTokens(userSearch)
{
	//alert('UserQuery_ParseTokens :'+ userSearch);
	var pos				= 0;
	var parseOK			= true;
	var lastParsedToken	= null;

	userSearch = userSearch.toLowerCase();
	userSearch = userSearch.replace(/'/g,'"');

	while (userSearch && (userSearch.length > 0))
	{
		// The first search line does not handle internation characters, wheres the second one does
		// pos = userSearch.search(/\s*(\w+\*)|(\w+)|(["][^"]*["])|([\(\)])\s*/);
		pos = userSearch.search(/\s*([A-Za-z0-9_\u00C0-\u00FF]+\*)|([A-Za-z0-9_\u00C0-\u00FF]+)|(["][^"]*["])|([\(\)])\s*/);

		var tokenStr = "";
		if (pos >= 0)
		{
			userSearch = RegExp.rightContext;
			if (RegExp.$1.length > 0)
			 tokenStr = '"' + RegExp.$1 + '"';
			else if (RegExp.$2.length > 0)
			 tokenStr = RegExp.$2;
			else if (RegExp.$3.length > 0)
			 tokenStr = RegExp.$3;
			else if (RegExp.$4.length > 0)
			 tokenStr = RegExp.$4;
		}
		if (tokenStr.length > 0)
		{
			
			var token = this.GetToken(tokenStr);
			
			if ( lastParsedToken && (lastParsedToken.type == UserQuery.NOISEWORD) &&
				(token.type & UserQuery.BINARYOP) )
			{
				// skip this token since it joins a noise word
			}
			else if (token.type == UserQuery.NOISEWORD)
			{
				this.UnrollExpression(UserQuery.OPERATOR);
				lastParsedToken = token;
			}
			else
			{
				if (token.type == UserQuery.USERITEM)
				{
						
					if (this.GetLastToken() && (this.GetLastToken().type & UserQuery.EXPRESSION))
					{
						this.InsertDefaultOperator();
					}
				}
				else if ((token.type == UserQuery.NOTOP) && this.GetLastToken() && (this.GetLastToken().type & UserQuery.EXPRESSION))
				{
					this.AddToken(this.builtIn("and"));
				}
			
				this.AddToken(token);
				lastParsedToken = token;
			}
		}
		else
		{
			if (userSearch.search(/\S/) >= 0)
			{
				parseOK = false;
				this.error = "Illegal character found in search string: (" + userSearch + ")";
				break;
			}
			else
				userSearch = "";
		}
		
	}
	return parseOK;
}

function UserQuery_GetToken(tokenStr)
{


	var noisewords		= ("$,0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,about,after,all,also,an,and,another,any,are,as,at,be,because,been,before,being,between,both,but,by,came,can,come,could,did,do,does,each,else,for,from,get,got,had,has,have,he,her,here,him,himself,his,how,if,in,into,is,it,its,just,like,make,many,me,might,more,most,much,must,my,never,now,of,on,only,or,other,our,out,over,re,said,same,see,should,since,so,some,still,such,take,than,that,the,their,them,then,there,these,they,this,those,through,to,too,under,up,use,very,want,was,way,we,well,were,what,when,where,which,while,who,will,with,would,you,your").split(",")
	var token		= null;
	var i			= 0;
	var isNoiseWord	= false;

	token = this.builtIn(tokenStr);
	
	if (token==null)
	{
		token = new Object();

		isNoiseWord	= false;
		for ( i=0 ; i<noisewords.length ; i++ )	{
			if (noisewords[i] == tokenStr) {
				isNoiseWord	= true;
				break;
			}
		}

		if (isNoiseWord) {
			token.type = UserQuery.NOISEWORD;
		} else {
			token.type = UserQuery.USERITEM;
		}
		
		token.value = tokenStr;
	}
	return token;


	/*

	var token = null;
	
	token = this.builtIn(tokenStr);
	
	if (token==null)
	{
		token = new Object();
		
		if (NoiseWords.KeyExists(tokenStr))
			token.type = UserQuery.NOISEWORD;
		else
			token.type = UserQuery.USERITEM;
		
		token.value = tokenStr;
	}
	return token;

	*/
}

// For VBScript use
function NewUserQuery()
{
	return new UserQuery();
}


