// create server support object first, then get dtSearch Engine' server
// object.  This is to surpress Unsafe ActiveX Object warning dialog.
var serverSupport = new ActiveXObject("ServerSupport.SDEngineSupport");
var server = serverSupport.server;
var fileSupport = new ActiveXObject("IOSupport.SDFileSupport");

// create new search job object
var search_options = server.NewOptions();
var search_job = server.NewSearchJob();
var search_results = null;
var results_count = 0;
var is_valid_request = false;

// create XML and XSL DOM objects
var objXML = new ActiveXObject('MSXML2.DOMDocument.3.0');
var objXSL = new ActiveXObject('MSXML2.DOMDocument.3.0');
objXML.async = false;
objXSL.async = false;
objXML.validateOnParse = false;
objXSL.validateOnParse = false;

// constants used in this page
var DAYS_IN_WEEK = 7;
var DAYS_IN_MONTH = 30;
var BYTES_IN_KB = 1024;
var NEAR_MAX_DISTANCE = 5;

// Stemming support
var dtsSearchStemming = 0x0004;

// Localizable proximity keyword
//
// Note: 'near' is English keyword for proximity connector.
// For other languages, substitute this with appropriate word.
// Once set in here, it will become keyword for that language.
//
// Also, example in 'search_criteria_help_area.htm', 'sharp near copier'
// must be adapted accordingly.
var PROXIMITY_KEYWORD = "near";

// EXTERNALLY CALLABLE METHODS.
// THESE METHODS CAN BE CALLED EXTERNALLY WITHOUT COMPROMISING
// SEPARATION OF SEARCH ENGINE INDEPENDENT AND SPECIFIC CODE SEGMENTS.

// Note: this method itself does not display search results.
// Subsequent call to GetSearchResults() will display the results.

function ExecuteSearch(index_paths)
{
  // prescreen syntax for invalid quoted text
  is_valid_request = IsValidRequest();
  if(!is_valid_request)
    return false;
	
  var request = GetRequest();
  var file_conditions = GetFileConditions();
  var indexes = GetIndexesToSearch(index_paths);
  var max_files = GetAppValue("Preferences", "NumOfMatches");
  
  try
  {
    //search_options.StemmingRulesFile = "C:\\program files\\sharp\\sharpdesk\\searchresources\\enu\\SearchOptionsFiles\\stemming.dat";
	search_options.StemmingRulesFile = fileSupport.GetStemmingFileFullPath();
	//alert(search_options.StemmingRulesFile);

	search_options.Save();

    search_job.Request = request;
    search_job.FileConditions = file_conditions;
    search_job.IndexesToSearch = indexes;
    search_job.ResultsInMemory = true;
    search_job.MaxFilesToRetrieve = max_files;
	
	//Stemming support
	var stemming_state = GetAppValue("Preferences", "StemmingOption");
	if(stemming_state == "on")
	  search_job.searchFlags |= dtsSearchStemming;

    var is_error = search_job.Execute();
	if(is_error)
	  return false;
  
    search_results = search_job.Results;
    results_count = search_results.Count;
  }
  catch(e)
  {
    alert("ExecuteSearch: failed to execute search.");
	return false;
  }
  
  return true;
}

// display errors encountered during Search Execution.
function DisplaySearchErrors()
{
	if ( -1 == is_valid_request)
	{

	// This is specifically to handle the dtSerach key words
	// when dtSsearch key words are used, it throws different error 
	// message so making it consistent with other unsupported words

	 // 'error code 122' = 'no documents found error'
	 var error_message = GetErrorMessage(122);
	 alert(error_message);
	 return;	
	}


  if(!is_valid_request)
  {
    // 'error code 116' = 'syntax error'
    var syntax_error = GetErrorMessage(116);
	alert(syntax_error);
	return;
  }
  
  var errors = search_job.Errors;
  
  if(errors == null)
    return;

  if(errors.Count == 0)
  {
    // if no error encountered, but no documents are
	// retrieved, simulate 'No documents found' error
	// (this happens when empty search criteria is specified.
	//  in that case, search_job.Execute() still returns non-zero).
    if(results_count == 0)
	{
	  // 'error code 122' = 'no documents found error'
      var error_message = GetErrorMessage(122);
      alert(error_message);
	}	  
	return;
  }
  
  // displays dialog one-by-one for each error encountered.  
  for(var i = 0; i < errors.Count; i++)
  {
    var error_message = GetErrorMessage(errors.Code(i));
    alert(error_message);
  }
}

// retrieves a specified portion of search results as one page
// of HTML text.
// Note: this method assumes ExecuteSearch() is previously called.
function GetSearchResults(view_format, start, max_count)
{
  var xsl_file;
  var count;
    
  var results_str = "";
		
  // depending on view format, load appropriate xsl file
  if(view_format == "summary")
    xsl_file = "SSEResultsSummary.xsl";
  else if(view_format == "detail")
    xsl_file = "SSEResultsDetail.xsl";
  else
  {
    alert("Invalid dispaly format specified.");
    return results_str;
  }
	
  // range check for document counts for this page
  if(results_count == 0)
  {
    alert("No document matches with specified criteria.");
	return results_str;
  }
  else if(start > results_count)
  {
    alert("Results index out of bound.");
    return results_str;
  }
  else if(start + max_count - 1 > results_count)
    count = results_count - start + 1;
  else
    count = max_count;
	  
  try
  {
    //alert("start=" + start + ", count=" + count + ", total=" + results_count);
	var xml_text = GetResultSet(start, count);
    xml_text = GetProcInstructions() + GetNameSpacedXML(xml_text);
    objXML.loadXML(xml_text);
  }
  catch(e)
  {
    alert("error getting results in DisplayResults: " +
      e.number + " - " + e.description);
    return results_str;
  }
	
  try
  {
    // load the XSL and check for errors
    objXSL.load(xsl_file);
    if(objXSL.parseError.errorCode != 0)
    {
      results_str = ShowXSLParseError(objXSL);
      return results_str;
    }
	
	RemoveUnselectedFields(objXSL);
	
    // perform transformation
	var strResult = objXML.transformNode(objXSL);
  }
  catch(e)
  {
    alert("error transforming results in DisplayResults: " +
      e.number + " - " + e.description);
    return results_str;
  }
	
  // and display the results
  var strHeader = SetResultHeader(start, start + count - 1, results_count);
  results_str = strHeader;
  results_str += strResult;
  results_str += strHeader;
	
  return results_str;
}

// sort the entire search results from top to bottom
// (not just a page currently displayed) based on
// specified field and sort order.
function SortSearchResults(field, order)
{
  var order_mask;
  var use_sort_key = false;	// sort key used instead of field

  switch(field)
  {
	case "Match Score":
	  //order_mask = 0;  // dtsSortByScore
	  order_mask = 4096; // dtsSortBySortKey 
	  use_sort_key = true;
	  break;
    case "Hit Count":
	  order_mask = 16;  // dtsSortByHits
	  break;
    case "Document Name":
	  //order_mask = 4;  // dtsSortByName
	  order_mask = 4096; // dtsSortBySortKey 
	  use_sort_key = true;
	  break;
	case "Abstract":
	  order_mask = 512;  // dtsSortByTitle
	  break;
	case "Location":
	  //order_mask = 1024;  // dtsSortByLocation
	  order_mask = 4096; // dtsSortBySortKey 
	  use_sort_key = true;
	  break;
	case "Document Type":
	  //order_mask = 256;  // dtsSortByType
	  order_mask = 4096; // dtsSortBySortKey 
	  use_sort_key = true;
	  break;
	case "Document Size":
	  order_mask = 32;  // dtsSortBySize
	  break;
	case "Modification Date":
	  order_mask = 8;  // dtsSortByDate
	  break;
	default:
	  alert("SortSearchResults: Invalid field specified.");
	  return;		
  }

  // use custom value as sort key
  if(use_sort_key)
  {
    for(var i = 0; i < search_results.Count; i++)
    {
      search_results.GetNthDoc(i);	
      var doc_values = GetDocValues(search_results.DocDetails);	
	  var sort_key = "";
	  
	  switch(field)
	  {
	    case "Match Score":
		  // this method converts score into zero prefixed string
		  // so that comparison is correct (ex. 100 > 20)
		  sort_key = GetZeroPrefixedString(doc_values["_score"], 3);
		  break;
	    case "Document Name":
		  sort_key = doc_values["_displayName"];
		  break;
	    case "Location":
		  sort_key = doc_values["_filename"];
		  break;
		case "Document Type":
		  sort_key = GetTypeDisplay(doc_values["_typeId"], doc_values["_filename"]);
		  break;
		default:
          alert("SortSearchResults: Invalid field for sort key specified.");
          break;		
	  }
	  
	  // make comparison case insensitive
	  // (Note: dtsSortCaseInsensitive flag does not work
	  //  due to overflow of bit)
      search_results.SetSortKey(sort_key.toUpperCase());
    }
  }

  if(order == "ascending")
    order_mask += 2;  // dtsSortAscending;
  else if(order == "descending")
    order_mask += 0;  // dtsSortDescending;
  else
    alert("Sort order invalid");
  
  try
  {
    // reorder the entire results
    search_results.Sort(order_mask, "");
  }
  catch(e)
  {
    alert("SortSearchResults: sorting search results failed.");
  }
}

function GetDefaultSortOrder(field)
{
  var sort_order = "descending";
  
  switch(field)
  {
	case "Match Score":
	  sort_order = "descending";
	  break;
    case "Hit Count":
	  sort_order = "descending";
	  break;
    case "Document Name":
	  sort_order = "ascending";
	  break;
	case "Abstract":
	  sort_order = "ascending";
	  break;
	case "Location":
	  sort_order = "ascending";
	  break;
	case "Document Type":
	  sort_order = "ascending";
	  break;
	case "Document Size":
	  sort_order = "ascending";
	  break;
	case "Modification Date":
	  sort_order = "descending";
	  break;
	default:
	  alert("GetDefaultSortOrder: Invalid field specified.");
	  break;		
  }
  
  return sort_order;
}

// DO NOT CALL METHODS BELOW THIS COMMENT FROM EXTERNAL FILES.
// CALLING THESE METHODS EXTERNALLY WILL COMPROMISE
// SEPARATION OF SEARCH ENGINE INDEPENDENT AND SPECIFIC
// CODE, RESULTING COMPROMISED MAINTENABILITY.

// internal support methods

function GetRequest()
{
  values = GetValues("Criteria");
  
  var search_text = ConvertSearchText(values["SearchText"]);  
  var field_array = new Array();
  var index = 0;

  if(values["Title"] != "")
    field_array[index++] = "Title contains " + values["Title"];  
  if(values["Author"] != "")
    field_array[index++] = "Author contains " + values["Author"];  
  if(values["Subject"] != "")
    field_array[index++] = "Subject contains " + values["Subject"]; 
  if(values["Keyword"] != "")
    field_array[index++] = "Keywords contains " + values["Keyword"];
	
  // build a filter string by ANDing all file conditions specified
  var field_str = "";
  if(index > 0)
  {
    for(var i = 0; i < index; i++)
	{
      field_str += "(" + field_array[i] + ")"; 
	  if(i < index - 1)
	    field_str += " and ";
	}
  }

  var requst_str;
  
if( ( search_text == "*.* " ||  search_text == "*.*") && field_str == "")
   request_str = "*";
 else   if(search_text == "" && field_str == "")
    request_str = "";
  else if(search_text != "" && field_str == "")
    request_str = search_text;
  else if(search_text == "" && field_str != "")
    request_str = field_str;
  else
    request_str = search_text + " and " + field_str;
	
  return request_str;
}

function IsValidRequest()
{
  var search_text = GetValue("Criteria", "SearchText");
  var len = search_text.length;
  var quote_count = 0;
  var bracket_count = 0;
   
  var l_search_text = search_text.toLowerCase();

  // dtSearch key words which are giving diff error msg.
  var key_words = "near or not and";

  // Checking whether the search word is one of the above key words
  var ret = key_words.indexOf(l_search_text);
  if ( ret != -1)
  {
	// specific error to handle the key word issues
	return -1;
  }
  

  // count how many quotes in the string
  // (must be either 0 or 2)
  for(var i = 0; i < len; i++)
  {
	if(search_text.charAt(i) == '"')
	  quote_count++;
	
	if(search_text.charAt(i) == '(' || search_text.charAt(i) == ')')
		bracket_count++;
  }
  
  // if no quotes/brackets, it is valid text
  if( ( quote_count ==   0 ) &&
	  ( bracket_count == 0 ) 
	)
		return true;	
	
  // allows opening and closing quotes
  // only at beginning and end of text
  if(quote_count == 2 &&
     search_text.charAt(0) == '"' &&
	 search_text.charAt(len-1) == '"')
	 return true;
  
  // allows opening and closing of brackets
  // only at beginning and end of text
  if(bracket_count == 2 &&
     search_text.charAt(0) == '(' &&
	 search_text.charAt(len-1) == ')')
	 return true;
	 
  return false;

}

function ConvertSearchText(orig_text)
{
  var token_array = Tokenize(orig_text);
  var proc_array = ProcessToken(token_array);
  var conv_text = Serialize(proc_array);
  
  return conv_text;
}

function Tokenize(text)
{
  // delimit string with combination of double-quoted strings
  // and space delimited words
  var token_array = text.match(/("[^"]*")|(\S+)/g);  
  return token_array;
}

function ProcessToken(token_array)
{
  if(token_array == null)
    return null;
	
  var length = token_array.length;
  
  // replaces PROXIMITY_KEYWORD (in English 'near') with 'w/5'
  for(var i = 0; i < length; i++)
  {
    if(token_array[i].toLowerCase() == PROXIMITY_KEYWORD)
      token_array[i] = "w/" + NEAR_MAX_DISTANCE;
  }

  var proc_array = new Array();
  var count = 0;

  // add "and" token between all tokens only if
  // prev. and next tokens are both non-keyword
  for(var i = 0; i < length; i++)
  {
    proc_array[count++] = token_array[i];
	
	if(i < length - 1)
	{
	/*
      if(!IsReservedWord(token_array[i]) &&
	     !IsReservedWord(token_array[i+1]))
	  {
	    proc_array[count++] = "and";
	  }
	*/
      if(!IsReservedWord(token_array[i]))
	  {
	     if(!IsReservedWord(token_array[i+1]) ||
		    IsPrefixableReservedWord(token_array[i+1]))
	     {
	       proc_array[count++] = "and";
		 }
	  }
	}
  }
    
  return proc_array;
}

function IsReservedWord(token)
{
  // is token keyword or
  // isolated '(' or ')' character?
  switch(token.toLowerCase())
  {
    case "and":      return true;
	case "or":       return true;
	case "not":      return true;
	case "contains": return true;
	case "(":        return true;
	case ")":        return true;
  }
  
  // is proximity operator w/d, d=1,2,3...
  if(token.match(/\bw\/\d+\b/i) != null)
    return true;
	
  return false;
}

function IsPrefixableReservedWord(token)
{
  // token keyword that can be prefixed by "and"
  switch(token.toLowerCase())
  {
    case "not":
	case "(":
	  return true;
  }
  
  return false; 
}

function Serialize(proc_array)
{
  if(proc_array == null)
    return "";

  // create a string by adding single space
  // between tokens	
  var req_text = "";  
  for(var i = 0; i < proc_array.length; i++)
  {
    req_text += proc_array[i];
	req_text += " ";
  }
	
  return req_text;
}

function GetFileConditions()
{
  values = GetValues("Criteria");
  
  var param_array = new Array();
  var index = 0;
  
  if(values["FileName"] != "")
  {
    param_array[index++] =
	  "name " + "\"*" + values["FileName"] + "*\"";
  }
  
  if(values["FilePath"] != "")
  {
    param_array[index++] =
	  "name " + "\"" + values["FilePath"] + "*\"";
  }
  
  if(values["FileType"] != "none")
  {
    // Note: Incomplete, does not work for multiple extensions case
	var type = values["FileType"];
    param_array[index++] =
	  "name " + "\"" + "*" + values["Types/" + type] + "\"";
  }
  
  switch(values["ModOption"])
  {
    case "none":
	  break;
	case "between":
	  // Note: GetDTDate() assumes input date to be English (MM/DD/YYYY) format
	  // (needs to be re-written for other date format)
	  param_array[index++] =
	    "date " + "\"" + GetDTDate(values["ModStart"]) +
		"~~" + GetDTDate(values["ModEnd"]) + "\"";
	  break;
	case "previous":
	  switch(values["ModPreviousOption"])
	  {
	    case "none":
		  break;
		case "days":
		  param_array[index++] =
		    "date " + "\"" + "T-" + values["ModPrevious"] + "~~T+0" + "\"";
		  break;
		case "weeks":
		  param_array[index++] =
		    "date " + "\"" + "T-" + values["ModPrevious"] * DAYS_IN_WEEK +
			"~~T+0" + "\"";
		case "months":
		  param_array[index++] =
		    "date " + "\"" + "T-" + values["ModPrevious"] * DAYS_IN_MONTH +
			"~~T+0" + "\"";
		  break;
		default:
		  alert("Invalid value specified for ModPrviousOption");
		  break;
	  }
	  break;
	default:
	  alert("Invalid value specified for ModOption");
	  break;
  }
  
  switch(values["FileSizeOption"])
  {
    case "none":
	  break;
	case "at_least":
	  param_array[index++] =
	    "size " + "\"" + values["FileSize"] * BYTES_IN_KB + "~~" + "\"";
	  break;
	case "at_most":
	  // requires 0~~ although for at_least case, do not need upper value
	  param_array[index++] =
	    "size " + "\"" + "~" + values["FileSize"] * BYTES_IN_KB + "~~" + "\"";
	  break;
	default:
	  alert("Invalid value specified for FileSizeOption");
	  break;
  }

  // build a filter string by ANDing all file conditions specified
  var filter_str = "";

  if(index > 0)
  {
    for(var i = 0; i < index; i++)
	{
      filter_str += "xfilter(" + param_array[i] + ")"; 
	  if(i < index - 1)
	    filter_str += " and ";
	}
  }

  return filter_str;
}

function GetIndexesToSearch(index_paths)
{
  var indexes_str = "";
  
  for(var i = 0; i < index_paths.length; i++)
  {
	// surround path by " characters, then append space
	// (surround by quote is needed because space may be in path)
	indexes_str += "\"";
	indexes_str += index_paths[i];
	indexes_str += "\" ";
  }

  return indexes_str;
}

function GetResultSet(start, count)
{
  var xml_str = "<Results>";
  
  for(var i = start; i < start + count; i++)
  {
    // i is one-based, while GetNthDoc() is zero based
    search_results.GetNthDoc(i - 1);		
	var doc_values = GetDocValues(search_results.DocDetails);
	
	// title field is invalid for OCRed text, so replace with file name
	doc_values["_title"] =
	  MakeTitleForFile(doc_values["_filename"], doc_values["_typeId"], doc_values["_title"]);
 
    // clear display name and short name fields just in case these include
	// non-printable characters 
    doc_values["_displayName"] = CleanField(doc_values["_displayName"]);
    doc_values["_shortName"] = CleanField(doc_values["_shortName"]);
	doc_values["_location"] = CleanField(doc_values["_location"]);
	
	var xml_doc_str =
      "<Result>" +
        "<DocId>" + "Doc" + i + "</DocId>" +
        "<FileName>" + MakeCDATA(doc_values["_filename"]) + "</FileName>" +
        "<DisplayName>" + MakeCDATA(doc_values["_displayName"]) + "</DisplayName>" +
        "<Title>" + MakeCDATA(doc_values["_title"]) + "</Title>" +
        "<Score>" + MakeCDATA(doc_values["_score"]) + "</Score>" +
        "<HitCount>" + MakeCDATA(GetHitCountDisplay(doc_values["_hitcount"])) + "</HitCount>" +
        "<Size>" + MakeCDATA(GetSizeDisplay(doc_values["_size"])) + "</Size>" +
        "<WordCount>" + MakeCDATA(doc_values["_wordcount"]) + "</WordCount>" +
		"<Type>" + MakeCDATA(GetTypeDisplay(doc_values["_typeId"], doc_values["_filename"])) + "</Type>" +
        "<Date>" + MakeCDATA(doc_values["_date"]) + "</Date>" +
        "<GenericDate>" + MakeCDATA(doc_values["_genericDate"]) + "</GenericDate>" +
        "<Time>" + MakeCDATA(doc_values["_time"]) + "</Time>" +
        "<Index>" + MakeCDATA(doc_values["_iindex"]) + "</Index>" +
        "<IndexPath>" + MakeCDATA(doc_values["_indexPath"]) + "</IndexPath>" +
        "<ShortName>" + MakeCDATA(doc_values["_shortName"]) + "</ShortName>" +
        "<Location>" + MakeCDATA(doc_values["_location"]) + "</Location>" +
		"<Active>" + MakeCDATA(GetActiveState(doc_values["_filename"])) + "</Active>" +
      "</Result>";
	  
	xml_str += xml_doc_str;
  }  
  xml_str += "</Results>";  
  return xml_str;
}

function CleanField(field_text)
{
  if(fileSupport.IsValidString(field_text))
    return field_text;
  return "";
}

function MakeTitleForFile(file_name, type_id, title_field)
{
  // if no junk character in title_field, do nothing
  if(fileSupport.IsValidString(title_field))
    return title_field;

  var file_name_ext = file_name.split(".");
  var file_ext = file_name_ext[1].toLowerCase();

  // list of files OCRed must match with the one
  // specified in MakeOcrTextViewerInfo() of
  // OcrTextParser Component, plus
  // *.tex and *.wks files whose title attribute
  // are also non-readable
  switch(file_ext)
  {
    case "tif":
	case "tiff":
	case "bmp":
	case "jpg":
	case "fpx":
	case "png":
	case "pcx":
	case "dcx":
	case "wfx":
	case "fax":
	case "psd":
	case "sdf":
	  title_field = "OCR Processed Image Filename:\n" + file_name;
	  break;
	case "tex":
	  title_field = "TEX Document Filename:\n" + file_name;
	  break;
	case "wks":
	  title_field = "Microsoft Works Filename:\n" + file_name;
	  break;
	// if other known file type, return empty string
	case "emf":
	case "msp":
	case "pub":
	case "rcf":
	case "sgm":
	case "tex":
	case "txt":
	case "vcf":
	case "wmf":
	default:
	  title_field = "";
	  break;
  }
  
  /*
  if(type_id >= 201 && type_id <= 239)
  {
    // if internally supported file,
	// do nothing further
  }
  else
  {
    // if unsupported, unrecognized file,
	// put blank text into title field to
	// prevent junk chars. getting into the field
    title_field = "";
  }
  */
	
  return title_field; 
}

// preserve <, >, and & characters in the string
// (without this, the entire XML string fails to be parsed)
function MakeCDATA(value_str)
{
  return "<![CDATA[" + value_str + "]]>";
}

function GetHitCountDisplay(value)
{
  var value_str;
  
  // if documents are not retrieved
  // based on content text, hit count
  // is not applicable
  if(search_job.Request == "")
    value_str = "N/A";
  else
    value_str = value;
	
  return value_str;
}

function GetSizeDisplay(value)
{
  return Math.ceil(value / BYTES_IN_KB);
}

// Note: C/C++ API has this method, but currently
// no access to the API, so it is duplicated here
function GetTypeDisplay(value, file_name)
{
  // force conversion to number
  // Note: valueOf() does not work here.
  // "+ 0" does not work either.
  var value_num = value - 0;

  // For old ppt files the id returned is varying so in that 
  // case checking whether the file type is ppt or not
/*var fileext = file_name.split(".");
  var fileext2lower = fileext[1].toLowerCase();
  if ( (value_num == 228 ) || ( value_num == 225) )
  {
	  if (fileext2lower == "ppt")
	  {
        	value_num = 230;
	  }
  }
*/
  // check against internally handled file types
  switch(value_num)
  {
    case 201:	return "Ami";
    case 202:	return "Ansi";
    case 203:	return "Ascii";
    //case 204:	return "Binary";
    case 205:	return "Office";
    case 206:	return "XBase";
    //case 207:	return "Binary (filtered)";
    case 208:	return "Hypertext";
    case 209:	return "Microsoft Word";
    case 210:	return "Microsoft Workstype";
    case 211:	return "Multimate";
    case 212:	return "RTF";
    case 213:	return "WordStar 2000";
    case 214:	return "WordStar";
    case 215:	return "Write";
    case 216:	return "Microsoft Word";
    case 217:	return "Microsoft Word";
    case 218:	return "WordPerfect 4.2";
    case 219:	return "WordPerfect 5";
    case 220:	return "WordPerfect";
    case 221:	return "WordStar";
    case 222:	return "XyWrite";
    case 223:	return "ZIP";
    case 224:	return "Document Summary";
    case 225:	return "Microsoft Excel";
    case 226:	return "HTML";
    case 227:	return "PDF";
    case 228:	return "Microsoft Word";
    case 229:	return "Microsoft Excel";
    case 230:	return "Microsoft PowerPoint";
    case 231:	return "HTML";
    case 232:	return "Database Record";
    case 233:	return "Segmented Text";
    case 234:	return "XML";
    case 235:	return "WordPerfect";
    case 236:	return "Unicode";
    case 237:	return "Eudora Message";
    case 238:	return "UTF-8";
    case 239:	return "DjVu";
	default:	break;
  }

  var file_name_ext = file_name.split(".");
  var file_ext = file_name_ext[file_name_ext.length-1].toLowerCase();

  // check against externally handled (OCRed) file types
  switch(file_ext)
  {
	case "bmp":		return "Bitmap Image";
	case "dcx":		return "DCX Image";
	case "fax":		return "WinFax Document";
	case "fpx":		return "FPX Image";
	case "jpg":		return "JPEG Image";
	case "pcx":		return "PCX Image";
	case "png":		return "PNG Image";
	case "psd":		return "Photoshop Document";
	case "sdf":		return "Composer Document";
    case "tif":		return "TIF Image";
	case "tiff":	return "TIF Image";
	case "wfx":		return "WinFax Document";
	default:		break;
  }
  // check against other known file types
  switch(file_ext)
  {
    //case "dat":		return "Generic File";
	case "emf":		return "EMF Image";
	case "msp":		return "Microsoft Patch File";
	case "pub":		return "Microsoft Publisher";
	case "rcf":		return "RCF Document";
	case "sgm":		return "SGM Document";
	case "tex":		return "LaTeX Document";
	case "txt":		return "Text Document";
	case "vcf":		return "vCard File";
	case "wmf":		return "WMF Image";
	default:		break;
  }
  
  // fallback, display XXX File where XXX=actual extension
  var default_name = file_ext.toUpperCase() + " File";
  return default_name;
}

// examine whether this file is active.
// (active means that file currently exists, and
//  therefore render it so that it can be opened
//  and drag-and-droped).
function GetActiveState(file_name)
{
  if(fileSupport.FindFile(file_name))
    return "true";
  return "false";
}

// this method assumes conversion of date in English to
// locale independent form.  If date is specified in different
// format, this method needs to be re-written
function GetDTDate(date)
{
  var format_date = "";
  
  var date_array = date.split("/");
  if(date_array.length != 3)
  {
    alert("GetDTDate: wrong format for date string specified.");
    return format_date;
  }
 
  // assumes date is in MM/DD/YYYY format 
  var month = date_array[0];
  var day = date_array[1];
  var year = date_array[2];
  
  // this format is recognized by dtSearch as locale independent
  format_date = "M" + month + "/" + "D" + day + "/" + "Y" + year;
  return format_date;
}

function GetDocValues(doc_details)
{
  var name_value_array = doc_details.split(/\r\n/);
  var value_array = new Array();
  
  var _displayname_filename = "";

  for(var i = 0; i < name_value_array.length; i++)
  {
    var name_value = name_value_array[i].split(/ = /);
	var name = name_value[0];
	var value = name_value[1];
	
	if ( "_filename" == name )
	{
		var nIndex = value.lastIndexOf("\\");
		if ( -1 != nIndex )
		{
			_displayname_filename = value.slice(nIndex + 1);
		}
	}

	// The inbuilt feature of dtSearch in associating the value of 'Title' in place of the _displayName for PDF and 
	// HTML files has been overrided; for Bug #3320
	if ( "_displayName" == name && "" != _displayname_filename )
	{
		value = _displayname_filename;	
	}

	value_array[name] = value;		
  }
  
  return value_array;
}

function SetResultHeader(start, count, total)
{
  var header = '<table width="100%" border="0" cellspacing="2" cellpadding="2">' +
                 '<tr>' + 
                 '<td width="84%">' +
                   '<b>' + start + ' - ' + count + ' of ' + total + ' matches.</b>' +
                 '</td>' +
                 '<td width="16%">' + 
                   '<div align="right">' +
				     '<a id="previous_page" href="">Previous</a>&nbsp;&nbsp;' + 
                     '<a id="next_page" href="">Next</a>' +
				   '</div>' +				   
                 '</td>' +
                 '</tr>' +
               '</table>';
  return header;			   
}

function GetProcInstructions()
{
  var inst_text =
    '<?xml version="1.0" standalone="yes"?>' +
	'<!DOCTYPE Results [<!ENTITY nbsp "&#160;"><!ENTITY images "Images/">]>' +
	'<?xml-stylesheet type="text/xsl" href="SseResultsDetail.xsl"?>';	
  return inst_text;
}

function GetNameSpacedXML(xml_text)
{
  var ns_text = xml_text.replace("<Results>",
    "<Results xmlns='urn:www-sharplabs-com:sse:search'>"); 
  return ns_text;
}

function ShowXSLParseError(objDoc)
{
  // create the error message
  var error_str = new String;
  error_str = 'Invalid XML file! <br />' +
			 'File URL: ' + objDoc.parseError.url + '<br />' +
			 'Line No.: ' + objDoc.parseError.line + '<br />' +
			 'Character: ' + objDoc.parseError.linepos + '<br />' +
			 'File position: ' + objDoc.parseError.filepos + '<br />' + 
			 'Source text: ' + objDoc.parseError.srcText + '<br />' + 
			 'Error code: ' + objDoc.parseError.errorCode + '<br />' + 
			 'Description: ' + objDoc.parseError.reason;
			   
  return error_str;
}

function RemoveUnselectedFields(xml_dom)
{
  var root = xml_dom.documentElement;  
  var fields = GetAppValues("Preferences/Fields");
  
  var del_values = new Array();
  var del_count = 0;
  
  for(field in fields)
  {
    if(fields[field] == "false")
	  del_values[del_count++] = field;
  }
  
  if(del_count > 0)
    RemoveNodesWithAttrib(root, "class", del_values);
}

// remove nodes which have corresponding attribute value(s)
// from xml node.  for example, if node is specified as
//
// ...<span class="my_class">...</span>...
//
// then calling...
// var values = new Array();
// values[0] = "my_class";
// values[1] = "your_class";
// RemoveNodesWithAttrib(top_node, "class", values)
//
// removes this node (assuming top_node is the higher-level
// node of this node.
//
// For multiple attribute values case such as
//
// ...<span class="my_class,your_class">...</span>...
//
// then executing the same code as before will remove
// this node (provided all elements of values array matches
// with class attribute delimited by ',' character(s).
function RemoveNodesWithAttrib(node, attrib, values)
{
  var atts = node.attributes;
  
  // if attribute setting for this node exists
  if(atts != null)
  {
    var att = atts.getNamedItem(attrib);
	
	// if corresponding attribute name exists
    if(att != null)
	{
	  // value of attribute may be concatenated
	  // ex. attrib="date,time,place..."
	  var vals = att.value.split(',');
	  var count = 0;
	  
	  for(var i = 0; i < vals.length; i++)
	  {		
		for(var j = 0; j < values.length; j++)
		{
          if(vals[i] == values[j])
		  {
	        count++;
			break;
		  }
		}		
	  }
	  
	  // only when all attributes in node matches,
	  // remove this node. for single attribute case,
	  // if node attribute value matches with specified
	  // attribute value, remove the node.
	  if(count == vals.length)
	    return true;
	}
  }
  
  var new_child = node.firstChild;
  var current_child = null;
  
  // recursively search for matched node by width first
  // search.  when found, just return true, then
  // remove the node, then go to next sibling node.
  while(new_child)
  {
    current_child = new_child;
	new_child = new_child.nextSibling;
	
    if(RemoveNodesWithAttrib(current_child, attrib, values))
	  node.removeChild(current_child);
  }
  
  return false;
}

// get user readable error message knowing error code
function GetErrorMessage(error_code)
{
  var text = "";
  
  switch(error_code)
  {
    case 1:		// index file access error
	  text += "Search engine could not access index(es).";
	  text += "\n";
	  text += "Make sure that Index Database(s) specified is not moved/deleted.";
      break;
	case 116:	// syntax error
	  text += "Syntax error(s) in Search Criteria was detected.";
	  text += "\n";
	  text += "Refer to Quick Help (?) at top-left of the page.";
	  break;
	case 122:	// no documents found
	  text += "No documents were found.";
	  text += "\n";
	  text += "Review Search Criteria and Index Database selection, and try again.";
	  break;
	case 137:	// too many unique words
	  text += "Too many unique words were matched.";
	  text += "\n";
	  text += "Review Search Criteria, and avoid using '*' character if you can.";
	  break;
	default:	// unknown error
	  text += "Error condition was detected, but cound not be identified.";
	  break;
  }
  
  return text;
}

function GetZeroPrefixedString(value, max_num_digits)
{
  var ret_value = value;
  var len = value.length;
  
  // if value is smaller than max. number of digits,
  // prefix it by leading zero(s)
  if(len < max_num_digits)
  {
    for(var i = 0; i < (max_num_digits - len); i++)
	  ret_value = "0" + ret_value;
  }
  
  return ret_value;
}
