// ----------------------------------------------------------------------------
// Zoom Search Engine 2.0 (7/8/2003)
//
// This file (search.js) is the JavaScript search front-end for client side 
// searches using index files created by the Zoom Search Engine Indexer.
//
// email: zoom@wrensoft.com
// www: http://www.wrensoft.com
//
// Copyright (C) Wrensoft 2000-2003
//
// This script performs client-side searching with the index data file
// (zoom_index.js) generated by the Zoom Search Engine Indexer. It allows you
// to run searches on mediums such as CD-ROMs, or other local data, where a
// web server is not available.
//
// We recommend against using client-side searches for online websites because
// it requires the entire index data file to be downloaded onto the user's 
// local machine. This can be very slow for large websites, and our server-side
// search scripts (search.php and search.asp) are far better suited for this.
// However, JavaScript is still an option for smaller websites in a limited
// hosting situation (eg: no php or asp)
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
// Settings (change if necessary)
// ----------------------------------------------------------------------------

// Highlight matched words in results
var Highlighting = 0;              // 0 = off, 1 = on
var HighlightColor = "#FFFF40";    // Highlight colour

// The options available in the dropdown menu for number of results
// per page
var PerPageOptions = new Array(10, 20, 50, 100);

var FormFormat = 1;    //0 = No search form (note that you must pass parameters to 
                   	   //    the script directly from elsewhere on your website).
                       //1 = Basic search form
                       //2 = Advanced search form (with options)

                                   
var OutputStyle = 1;	//0 = Basic Style, Page Title, Score and URL
    	                //1 = Descriptive Style, Match number, Page Title,
        	            //    Page description, Score and URL                

var ZoomInfo = 0;		//0 = Don't display Zoom info line at bottom of search
                    	//1 = Display Zoom info line at bottom of search
 
var WordSplit = 1; 		//0 = Only split input search phrase into words when a
                    	//    Space character is found
                    	//1 = Split input search phrase at Space ' ',
                    	//    UnderScore '_' , Dash '-' and Plus '+' characters

// ----------------------------------------------------------------------------
// Helper Functions
// ----------------------------------------------------------------------------
   	         
// This function will return the value of a GET parameter 
function getParam(paramName) 
{
	paramStr = document.location.search;
	if (paramStr == "") 
		return "";
	
	// remove '?' in front of paramStr
	if (paramStr.charAt(0) == "?")
		paramStr = paramStr.substring(1, paramStr.length);
				
	arg = (paramStr.split("&"));
	for (i=0; i < arg.length; i++) {
		arg_values = arg[i].split("=")
		if (unescape(arg_values[0]) == paramName) {
			return unescape(arg_values[1]);
		}
	}	
	return;
}

// Compares the two values, used for sorting output results
// Results that match all search terms are put first, highest score
function SortCompare (a, b) 
{
	if (a[2] < b[2]) return 1;
  	else if (a[2] > b[2]) return -1;
    else if (a[1] < b[1]) return 1;
    else if (a[1] > b[1]) return -1;
    else return 0;    
} 

function pattern2regexp(pattern) {
	pattern = pattern.replace(/\*/g, ".*");
	pattern = pattern.replace(/\?/g, ".?");
	return "\\b" + pattern + "\\b";
}
		
function HighlightDescription(line) { 	    
    res = line;            
    for (i = 0; i < matchwords_num; i++) {
    	// replace with marker text, assumes [;:] and [:;] is not the search text...    	    	    	
    	res = res.replace(new RegExp("\\b("+matchwords[i]+")\\b", "gi"), "[;:]$1[:;]");    	    	
    }    
    // replace the marker text with the html text
    // this is to avoid finding previous <span>'ed text.    
    res = res.replace(/\[;:\]/g, "<span style=\"background: " + HighlightColor + "\">");
    res = res.replace(/\[:;\]/g, "</span>");
    return res;
}

// ----------------------------------------------------------------------------
// Parameters initialisation (globals)
// ----------------------------------------------------------------------------

var query = getParam("zoom_query");
query = query.replace(/\+/g, " ");	// replace the '+' with spaces 

var per_page = parseInt(getParam("zoom_per_page"));
if (isNaN(per_page)) per_page = 10;

var page = parseInt(getParam("zoom_page"));
if (isNaN(page)) page = 1;
	
var andq = parseInt(getParam("zoom_and"));
if (isNaN(andq)) andq = 0;

var searchWords = new Array();
var data = new Array();
var output = new Array();

if (Highlighting == 1) {
	var matchwords = new Array();
	var matchwords_num = 0;
}


// ----------------------------------------------------------------------------
// Main search function starts here
// ----------------------------------------------------------------------------

function ZoomSearch() {
	
	// Display the form
	if (FormFormat > 0) {
		document.writeln("<form method=\"GET\" action=\"" + document.location.pathname + "\">");
		document.writeln("<input type=\"text\" name=\"zoom_query\" size=\"20\" value=\"" + query + "\">");
		document.writeln("<input type=\"submit\" value=\"Search\">");
    	if (FormFormat == 2) {
	        document.writeln("<small>Results per page:");
	        document.writeln("<select name='zoom_per_page'>");
	        for (i = 0; i < PerPageOptions.length; i++) {
	        	document.write("<option");
	        	if (PerPageOptions[i] == per_page)
	        		document.write(" selected=\"selected\"");
	        	document.writeln(">" + PerPageOptions[i] + "</option>");
	        }	            		        
	        document.writeln("</select></small></p>");
	        document.writeln("<small>Match: ");
	        if (andq == 0) {
	            document.writeln("<input type=\"radio\" name=\"zoom_and\" value=\"0\" checked>any search words");
	            document.writeln("<input type=\"radio\" name=\"zoom_and\" value=\"1\">all search words");
	        } else {
	            document.writeln("<input type=\"radio\" name=\"zoom_and\" value=\"0\">any search words");
	            document.writeln("<input type=\"radio\" name=\"zoom_and\" value=\"1\" checked>all search words");
	        }
	        document.writeln("</small>");
	    }
    	document.writeln("</form>");
    }

	// give up early if no search words provided
	if (query.length == 0) {
		//document.writeln("No search query entered.<br>");
		if (ZoomInfo == 1)
			document.writeln("<center><small>Search powered by <a href=\"http://www.wrensoft.com/zoom\"><b>Zoom Search Engine</b></a></small><br></center>");
		return;
	}
			
	if (WordSplit == 1) 
		query = query.replace(/[+-_]/g, " "); // replace '+', '-', '_' with spaces.
	
	// split search phrase into words	
	searchWords = query.split(" ");	// split by spaces.
	
	document.writeln("<h2>Search Results for \"" + query + "\"</h2>");
	
	numwords = searchWords.length;	
	kw_ptr = 0;
	outputline = 0;
	usewildcards = 0;
	ipage = 0;
	
	for (sw = 0; sw < numwords; sw++) {		
		
		re = new RegExp(pattern2regexp(searchWords[sw]), "gi");
	
		for (kw_ptr = 0; kw_ptr < keywords.length; kw_ptr++) {
			data = keywords[kw_ptr].split(",");	
			
			
			//match_result = searchWords[sw] == data[0];		
			match_result = data[0].search(re);
						
			if (match_result != -1) {								
				// keyword found, include it in the output list
				// todo: highlighting				
				
			    if (Highlighting == 1) {
             		// Add to matched words list             		             		
             		// Check if its already in the list
             		for (i = 0; i < matchwords.length && matchwords[i] != data[0]; i++);       			             	
             		if (i == matchwords.length)	// not in list
             			matchwords_num = matchwords.push(data[0]);             		             		             		
            	}
            	
				for (kw = 1; kw < data.length; kw += 2) {
					// check if page is already in output list
					pageexists = 0;					
					ipage = data[kw];																		
					for (ol = 0; ol < outputline; ol++) {						
						
						if (output[ol][0] == ipage) {
							// page is already in output list so add to count and extra
							if (output[ol][1] > 10000) {
								// take it easy if its too big (to prevent huge scores)
								output[ol][1] += 1;
							} else {
								output[ol][1] += parseInt(data[kw+1]);	// add in score
								output[ol][1] *= 2;				// double score as we have two words matching
							}
							output[ol][2] += 1;					// increase word match count
							pageexists = 1;
						}						
					}
					if (pageexists == 0) {
						// new page to add to list						
						// create 3 fields for each output
						output[outputline] = new Array(0,0,0);					
						// now fill in the values for each field
						output[outputline][0] = ipage;		// page index
						output[outputline][1] = parseInt(data[kw+1]);	// score
						output[outputline][2] = 1;			// single word match only
						outputline++;				
					}
										
				}
				// if (useWildCards == 0) 
				//break;	// this search word was found, so skip to next
			}
			// return to start of keywords list...		
		}	
	}
	
	// Get number of pages matched
	matches = outputline;
	
	// Sort results in order of score, use "SortCompare" function
	if (matches > 1)
		output.sort(SortCompare);

	// Count number of output lines that match ALL search terms
	oline = 0;
	fullmatches = 0;
	
	if (numwords > 1) {		
		while ((oline < matches)) {
			if (output[oline][2] == numwords) {
				fullmatches++;
			} 		
			oline++;
		}		
		if (andq == 1)
			matches = fullmatches;
	}
	
	//Display search result information
	document.writeln("<small>");
	if (matches == 1)
    	document.writeln("<i>1 result found.</i><br>");
	else if (matches == 0)
    	document.writeln("<i>No results found.</i><br>");
	else if (numwords > 1 && andq == 0) {
    	//OR
    	SomeTermMatches = matches - fullmatches;
    	document.writeln("<i>" + fullmatches + " pages found containing all search terms. ");
    	if (SomeTermMatches > 0)
        	document.writeln(SomeTermMatches + " pages found containing some search terms.");
    	document.writeln("</i><br>");
    }
	else if (numwords > 1 && andq == 1) //AND
    	document.writeln("<i>" + fullmatches + " pages found containing all search terms.</i><br>");
	else
    	document.writeln("<i>" + matches + " results found.</i><br>");
	
	document.writeln("</small>\n");
	
	// number of pages of results
	num_pages = Math.ceil(matches / per_page);
	if (num_pages > 1)
		document.writeln("<br>" + num_pages + " pages of results.<br>\n");
		
	// determine current line of result from the output array
	if (page == 1) {
		arrayline = 0;
		out_counter = 0;
		outStartsAt = 0;
	} else {
		//arrayline = ((page - 1) * per_page);
		arrayline = 0;
		out_counter = 0;
		outStartsAt = ((page - 1) * per_page);
	}
	
	// the last result to show on this page
	result_limit = outStartsAt + per_page;	
	
	// display the results
	while (arrayline < matches && arrayline < result_limit) {
				
		if ((andq == 1) && (numwords > 1) && (output[arrayline][2] < numwords)) {
			arrayline++;
			continue;				
		}
		
		out_counter++;		
		if (out_counter <= outStartsAt)
		{
			arrayline++;
			continue;
		}
		
		ipage = output[arrayline][0];		
		score = output[arrayline][1];		
		if (OutputStyle == 0) {
			// basic style
	        document.writeln("<p>Page: <a href=\"" + urls[ipage] + "\">" + titles[ipage] + "</a><br>\n");
	        document.writeln("Score: " + score + "&nbsp;&nbsp;<small><i>URL:" + urls[ipage] + "</i></small></p>\n");			
		} else {			
			// descriptive style
			document.writeln("<p><b>" + (out_counter) + ".</b>&nbsp;<a href=\"" + urls[ipage] + "\">" + titles[ipage] + "</a><br>");
			if (Highlighting == 1)
				document.writeln(HighlightDescription(descriptions[ipage]));
			else
				document.writeln(descriptions[ipage]);		
			document.writeln("...<br>\n");
			document.writeln("<font color=\"#999999\"><small><i>Terms matched: " + output[arrayline][2] + " Score: " + score + "&nbsp;&nbsp;URL: " + urls[ipage] + "</i></small></font></p>\n");
		}		
		arrayline++;
	}
	
	// Show links to other result pages
	if (num_pages > 1) {
    	document.writeln("<p>Result Pages: ");
    	if (page > 1)
        	document.writeln("<a href=\"" + document.location.pathname + "?zoom_query=" + query + "&zoom_page=" + (page-1) + "&zoom_per_page=" + per_page + "&zoom_and=" + andq + "\">&lt;&lt; Previous</a>&nbsp;");
	    
	    for (i = 1; i <= num_pages; i++) {
    	    if (i == page) {
    	    	document.writeln(page + "&nbsp;");        	
        	} else {
            	document.writeln("<a href=\"" + document.location.pathname + "?zoom_query=" + query + "&zoom_page=" + i + "&zoom_per_page=" + per_page + "&zoom_and=" + andq + "\">" + i + "</a>&nbsp;");
        	}
    	}

    	if (page != num_pages)
    		document.writeln("<a href=\"" + document.location.pathname + "?zoom_query=" + query + "&zoom_page=" + (page+1) + "&zoom_per_page=" + per_page + "&zoom_and=" + andq + "\">Next &gt;&gt;</a>&nbsp;");        	
    }

	document.writeln("<br><br>");
	
	if (ZoomInfo == 1)
		document.writeln("<center><small>Search powered by <a href=\"http://www.wrensoft.com/zoom\"><b>Zoom Search Engine</b></a></small><br></center>");
	
}

