/*
 * tokensearch.js: simple string token collection search
 *
 * (C) 2015 Michael Vogt
 * MIT LICENSE
 *
 */
 var Tokensearch = function(collection, options) {
  this.collection = collection;
  options = options || {};
  this.delimiter = options.delimiter || Tokensearch.defaultOptions.delimiter;
  this.maxFilterTokenEntries = options.maxFilterTokenEntries || Tokensearch.defaultOptions.maxFilterTokenEntries;
  this.threshold = options.threshold || Tokensearch.defaultOptions.threshold;
  this.collectionKeys = options.collectionKeys || Tokensearch.defaultOptions.collectionKeys;
  if (this.collectionKeys.length===0) {
    throw new Error('No collectionKeys defined!');
  }
  if (!this.collection || this.collection.length===0) {
    throw new Error('Empty collection!');
  }
  this.collectionDataTokenSize = this.collectionKeys.length;
  this._prepareSearchTokens();
};

Tokensearch.defaultOptions = {
  //split strings with the delimiter
  delimiter: ' ',

  // At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match
  // (of both letters and location), a threshold of '1.0' would match anything.
  threshold: 0.7,

  // How many search tokens are considered
  maxFilterTokenEntries: 5,

  // search key
  collectionKeys: []
};

Tokensearch.prototype._prepareSearchTokens = function() {
  var self = this;
  //Get all search tokens
  this.collection.forEach(function(entry) {
    var tmp = [];
    self.collectionKeys.forEach(function(key) {
      entry[key].trim().toLowerCase().split(self.delimiter).forEach(function(e) {
        tmp.push(e);
      });
    });
    entry.dataEntryTokens = tmp.filter(self._onlyUnique);
  });

};

Tokensearch.prototype._onlyUnique = function(value, index, self) {
  return self.indexOf(value) === index;
};

/**
 * returns an sorted array of { 'item': OBJECT, 'score': score }
 * -item contains the input object
 * -score defines the match with the search term, 0 means perfect match, 1 means rubbish
 */
Tokensearch.prototype.search = function(token, customThreshold) {
  var self = this;
  var searchTokens = [];
  var threshold = customThreshold || this.threshold;

  //make sure the search tokens contains no dups
  var tmp = token.trim().split(this.delimiter).filter(this._onlyUnique);
  for (var i = 0, len = Math.min(tmp.length, this.maxFilterTokenEntries); i < len; i++) {
    searchTokens.push(tmp[i].toLowerCase());
  }

  var resultTmp = [];
  var maxScore = 0;
  this.collection.forEach(function(entry) {
    var score = 0;

    entry.dataEntryTokens.forEach(function(dataEntryToken) {
      searchTokens.forEach(function(searchToken) {
        if (dataEntryToken.indexOf(searchToken) > -1) {
          score += (dataEntryToken === searchToken) ? 2 : 1;
        }
      });
    });

    if (score) {
      if (score > maxScore) {
        maxScore = score;
      }
      resultTmp.push({ 'item': entry, 'score': score });
    }
  });

  var result = [];
  var normalizedScore = 1 / maxScore;
  resultTmp.forEach(function(r) {
    r.score = 1-r.score*normalizedScore;
    if (r.score <= threshold) {
      result.push(r);
    }
  });

  return result.sort(function(a, b) {
     return a.score - b.score;
  });
};

module.exports = Tokensearch;

@@ -408,25 +408,32 @@
 ies;%0A  this.
-t
+defaultT
 hreshold = o
@@ -2137,17 +2137,24 @@
 %7C%7C this.
-t
+defaultT
 hreshold

make core more readable