// Search & highlight methods for
// Morten's JavaScript Tree Menu
// version $Id: search-highlight.js,v 1.1 2002/11/10 20:58:27 nettrom Exp $
// http://www.treemenu.com/

// Copyright (c) 2001-2002, Morten Wang & contributors
// All rights reserved.

// This software is released under the BSD License which should accompany
// it in the file "COPYING".  If you do not have this file you can access
// the license through the WWW at http://www.treemenu.com/license.txt

// Using this method requires a modified function MTMakeLink found below.
// The easiest way of access them are to include them through a script
// element _after_ mtmcode.js, example:
// <script type="text/javascript" src="search-highlight.js"></script>



// Have a wrapper function around searchHighlight() (so rename the latter)
// which sets matchedItems.  If its length > 0, iterate through it and
// set the highlight-property of each item
function searchHighlight(thisTree, thisString, theseCriteria, theseProperties) {	var matches = treeSearch(thisTree, thisString, theseCriteria, theseProperties);
	if(matches.length > 0) {
		for(var i = 0; i < matches.length; i++) {
			matches[i].highlight = true;
		}
	}
  else
    alert("Sorry - Did not find any matching entries"); 
	setTimeout('MTMDisplayMenu()', 10);
}

// Global methods for searching follows below this line
// ----------------------------------------------------

// isCaseSensitive is self-explanatory
// searchType is 0 for startsWith, 1 for contains and 2 for endsWith.
var isCaseSensitive, searchType, searchString, searchProps, matchedItems;
function treeSearch(thisTree, thisString, theseCriteria, theseProperties) {
	// This method searches through the _complete_ tree structure
	// given as the first argument looking for searchString.
	// theseCriteria is a comma-separated list of the criteria for
	// the search.  Whitespace between keywords is allowed.
	// The following keywords are recognized, and capitalization is not
	// required (so "casesensitive" will work just as well):
	//
	//     caseInsensitive
	//     caseSensitive
	//     startsWith
	//     endsWith
	//     contains
	//
	// (An improvement would be to also recognize 'regex[p]' meaning
	//  searchString is the regex to use and that's it)
	// (Another extension might be to take multiples of 3 arguments
	// each defining how to search, thereby making it possible
	// to search on multiple criteria in the same tree.
	//
	// Their meaning should be self-explanatory.
	//
	// theseProperties is a comma-separated list of which properties
	// to look for searchString in.  Recognized values are:
	//     text
	//     url
	//     target
	//     icon
	//     tooltip

	// Return value: an pointer to an array containing the matched items
	// (also available globaly as matchedItems).

	// First, set the different boolean search given by searchCriteria.
	var criterias = theseCriteria.split(",");
	var i;

	for(i = 0; i < criterias.length; i++) {
		// trim whitespace and convert to lowercase
		var myString = trimWhitespace(criterias[i]).toLowerCase();
		switch(myString) {
			case "caseinsensitive":
				isCaseSensitive = false;
				break;	
			case "casesensitive":
				isCaseSensitive = true;
				break;
			case "startswith":
				searchType = 0;
				break;
			case "contains":
				searchType = 1;
				break;
			case "endswith":
				searchType = 2;
				break;
		}
	}

	// Reset matched item array
	matchedItems = new Array();
	// create array of search properties
	searchProps = theseProperties.split(",");
	for(i = 0; i < searchProps.length; i++) {
		// trim whitespace and convert to lowercase
		searchProps[i] = trimWhitespace(searchProps[i]).toLowerCase();
	}
	searchString = thisString;
	if(!isCaseSensitive) {
		searchString = searchString.toLowerCase();
	}
	searchTree(thisTree);
	return matchedItems;
}

function searchTree(thisTree) {
	// search the tree thisTree looking for matches defined by
	// the global variables isCaseSensitive (boolean)
	// searchType (0 = startswith, 1 = contains, 2 = endsWith)
	// properties (array, strings holding each property to search)
	// for all items (childnodes)
	var i, j;
	for(i = 0; i < thisTree.items.length; i++) {
		// check all properties that need checking
		for(j = 0; j < searchProps.length; j++) {
			// eval("thisTree.items[" + i + "]." + properties[j];
			if(compareString(eval("thisTree.items[" + i + "]." + searchProps[j]), searchString)) {
				// add it to matchedItems[]
				matchedItems[matchedItems.length] = thisTree.items[i];
				// recurse up and expand all parentNodes
				expandUp(thisTree.items[i]);
			}
		}
		// if submenu, recurse down that submenu
		if(thisTree.items[i].submenu) {
			searchTree(thisTree.items[i].submenu)
		}
	}
}

function compareString(thisString, compareString) {
	// compares string thisString to compareString
	// according to the global search criteria variables.
	if(thisString) {
		if(!isCaseSensitive) {
			thisString = thisString.toLowerCase();
		}
		if(searchType == 0 && thisString.indexOf(compareString) == 0) {
			return true;
		} else if(thisString.indexOf(compareString) != -1) {
			if(searchType == 1) {
				return true;
			} else if(searchType == 2) {
				if((thisString.length - compareString.length) == thisString.indexOf(compareString)) {
					return true;
				}
			}
		}
	}
	return false;
}

function expandUp(thisItem) {
	while(thisItem.parentNode) {
		thisItem.parentNode.expanded = true;
		thisItem = thisItem.parentNode;
	}
}

function trimWhitespace(thisString) {
	var newString = thisString;
	if(newString.replace) {
		newString = newString.replace(/\s+/g, "");
	} else {
		while(newString.indexOf(" ") == 0) {
			newString = newString.substring(1);
		}
		while(newString.lastIndexOf(" ") == newString.length-1) {
			newString = newString.substring(0, newString.length-1);
		}
	}
	return newString;
}

