/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Lucene Search Query Constructor
// Author:  Kelvin Tan  (kelvint at apache.org)
// Version: $Id$
//
// Modified: Simon Pigot - do not group NOT/without queries when fieldName in
//                         use and obtain field name from class attribute and
//                         update to use prototype functions

// Change this according to what you use to name the field modifiers in your form.
// e.g. with the search field "name", the form element of its modifier 
// will be "name<modifierSuffix>"
var modifierSuffix = 'Modifier';

// If not a field-specific search
// e.g. with the arbitary form element 'foobar', its modifier will be 
// <noFieldPrefix>foobarModifier and its form element 
// will be <noFieldPrefix>foobar
var noFieldPrefix = 'noField-';

// Do you wish the query to be displayed as an alert box?
var debug = false;

// Do you wish the function to submit the form upon query construction?
var submitForm = false;

// prefix modifier for boolean AND queries
var AND_MODIFIER = '+';

// prefix modifier for boolean NOT queries
var NOT_MODIFIER = '-';

// prefix modifier for boolean OR queries
var OR_MODIFIER  = ' ';

var NO_MODIFIER = 0;

// default modifier for terms
var DEFAULT_TERM_MODIFIER = AND_MODIFIER;

// default modifier for groups of terms (denoted by parantheses)
var DEFAULT_GROUP_MODIFIER = AND_MODIFIER;

// used to delimit multiple values from checkboxes and select lists
var VALUE_DELIMITER = ' ';

// Constructs the query
// @param query Form field to represent the constructed query to be submitted
// @param debug Turn on debugging?
function doMakeQuery( frm, dbg )
{
  if(typeof(dbg) != "undefined")
    debug = dbg;
   
	var query = frm['query'];
  query.value = "";
  
  // keep track of the fields we've examined
  var dict = new Array();
  
  var formElements = frm.getElements();
  for(var i=0; i<formElements.length; i++) {
    var element = formElements[i];
    var elementName = element.readAttribute('name');
    if(elementName != "" && (dict.indexOf(elementName) == -1)) {
      dict[dict.length] = elementName;
      
      // ensure we get the whole group (of checkboxes, radio, etc), if applicable
      var elementValue = $F(frm[elementName]);
      if(elementValue.length > 0) {
        var subElement = frm[elementName + modifierSuffix];
        if(typeof(subElement) != "undefined") { // found a field/fieldModifier pair
          var termMod, groupMod;
          var modifier = $F(subElement);
          // modifier field is in the form <termModifier>|<groupModifier>
          if(modifier.indexOf('|') > -1) {
            var idx = modifier.indexOf('|');
            termMod = modifier.substring(0, idx);
            if(termMod == '') termMod = DEFAULT_TERM_MODIFIER;
            groupMod = modifier.substring(idx + 1);
            if(groupMod == '') groupMod = DEFAULT_GROUP_MODIFIER;
          } else {
            termMod = modifier;
            if(termMod == '') termMod = DEFAULT_TERM_MODIFIER;
            groupMod = DEFAULT_GROUP_MODIFIER;
          }
					luceneField = element.readAttribute('class');
          appendTerms(query, termMod, elementValue, luceneField, groupMod);
        }
      }
    }
  }

  if(debug) {alert('Query:' + $F(query));}
  
  if(submitForm) {
    frm.submit();
  } else {
    return query;
  }
}

// Constructs a Google-like query (all terms are ANDed)
// @param query Form field to represent the constructed query to be submitted
// @return Submits the form if submitOnConstruction=true, else returns the query param
function doANDTerms(query)
{
  var value = $F(query);
  query.value = "";
  appendTerms(query, AND_MODIFIER,  value);
  if(submitForm) {
    frm.submit();
  } else {
    return query;
  }
}

function buildTerms(termModifier, fieldValue)
{
  fieldValue = trim(fieldValue);
  var splitStr = fieldValue.split(" ");
  fieldValue = '';
  var inQuotes = false;
  for(var i=0;i<splitStr.length;i++) {
    if(splitStr[i].length > 0) {
      if(!inQuotes) {
        fieldValue = fieldValue + termModifier + splitStr[i] + ' ';
      } else { 
        fieldValue = fieldValue + splitStr[i] + ' ';
      }      
      if(splitStr[i].indexOf('"') > -1) inQuotes = !inQuotes
    }
  }
  fieldValue = trim(fieldValue);  
  return fieldValue;
}

// Appends terms to a query. 
// @param query Form field of query
// @param termModifier Term modifier
// @param value Value to be appended. Tokenized by spaces, 
//    and termModifier will be applied to each token.
// @param fieldName Name of search field. Omit if not a field-specific query.
// @param groupModifier Modifier applied to each group of terms.
// @return query form field
function appendTerms(query, termModifier, value, fieldName, groupModifier)
{
  if(typeof(groupModifier) == "undefined")
    groupModifier = DEFAULT_GROUP_MODIFIER;
  
  value = buildTerms(termModifier, value);
  
  // not a field-specific search
  if(fieldName == null || fieldName.indexOf(noFieldPrefix) != -1 || fieldName.length == 0)
  {
    if(groupModifier == NO_MODIFIER) {
      if($F(query).length == 0) {
        query.value = value;
      } else {
        query.value = $F(query) + ' ' + value;
      }  
    } else { 
      if($F(query).length == 0) {
        query.value = groupModifier + '(' + value + ')';
      } else {
        query.value = $F(query) + ' ' + groupModifier + '(' + value + ')';
      }  
    }
  } else {
		var newTerm = '';
  	if (groupModifier == NO_MODIFIER) groupModifier = '';

		// do not group NOT terms
		if (value.startsWith(NOT_MODIFIER)) {
			var notTerms = [];
			value.scan(/\w+/, function(match){ notTerms.push(match[0]) });
			notTerms.each(function(n) {
				newTerm += NOT_MODIFIER + fieldName + ':' + n + ' ';
			});
		} else {
			newTerm = groupModifier + fieldName + ':(' + value + ')';
		}
			
    if($F(query).length == 0) {
      query.value = newTerm;
    } else {
      query.value = $F(query) + ' ' + newTerm;
    }  
  }
  query.value = trim($F(query));
  return query;
}

function quote(value) // used in phrase queries
{
  return "\"" + trim(value) + "\"";
}

function trim(inputString) {
   if (typeof inputString != "string") { return inputString; }
   
   var temp = inputString;
   
   // Replace whitespace with a single space
   var pattern = /\s+/ig;
   temp = temp.replace(pattern, " ");
  
   // Trim 
   pattern = /^(\s*)([\w\W]*)(\b\s*$)/;
   if (pattern.test(temp)) { temp = temp.replace(pattern, "$2"); }
   // run it another time through for words which don't end with a character or a digit
   pattern = /^(\s*)([\w\W]*)(\s*$)/;
   if (pattern.test(temp)) { temp = temp.replace(pattern, "$2"); }
   return temp; // Return the trimmed string back to the user
}

