/*
 * language_data.js
 * ~~~~~~~~~~~~~~~~
 *
 * This script contains the language-specific data used by searchtools.js,
 * namely the list of stopwords, stemmer, scorer and splitter.
 *
 * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
 * :license: BSD, see LICENSE for details.
 *
 */

var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"];


/* Non-minified version is copied as a separate JS file, is available */

/**
 * Porter Stemmer
 */
var Stemmer = function() {

  var step2list = {
    ational: 'ate',
    tional: 'tion',
    enci: 'ence',
    anci: 'ance',
    izer: 'ize',
    bli: 'ble',
    alli: 'al',
    entli: 'ent',
    eli: 'e',
    ousli: 'ous',
    ization: 'ize',
    ation: 'ate',
    ator: 'ate',
    alism: 'al',
    iveness: 'ive',
    fulness: 'ful',
    ousness: 'ous',
    aliti: 'al',
    iviti: 'ive',
    biliti: 'ble',
    logi: 'log'
  };

  var step3list = {
    icate: 'ic',
    ative: '',
    alize: 'al',
    iciti: 'ic',
    ical: 'ic',
    ful: '',
    ness: ''
  };

  var c = "[^aeiou]";          // consonant
  var v = "[aeiouy]";          // vowel
  var C = c + "[^aeiouy]*";    // consonant sequence
  var V = v + "[aeiou]*";      // vowel sequence

  var mgr0 = "^(" + C + ")?" + V + C;                      // [C]VC... is m>0
  var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$";    // [C]VC[V] is m=1
  var mgr1 = "^(" + C + ")?" + V + C + V + C;              // [C]VCVC... is m>1
  var s_v   = "^(" + C + ")?" + v;                         // vowel in stem

  this.stemWord = function (w) {
    var stem;
    var suffix;
    var firstch;
    var origword = w;

    if (w.length < 3)
      return w;

    var re;
    var re2;
    var re3;
    var re4;

    firstch = w.substr(0,1);
    if (firstch == "y")
      w = firstch.toUpperCase() + w.substr(1);

    // Step 1a
    re = /^(.+?)(ss|i)es$/;
    re2 = /^(.+?)([^s])s$/;

    if (re.test(w))
      w = w.replace(re,"$1$2");
    else if (re2.test(w))
      w = w.replace(re2,"$1$2");

    // Step 1b
    re = /^(.+?)eed$/;
    re2 = /^(.+?)(ed|ing)$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      re = new RegExp(mgr0);
      if (re.test(fp[1])) {
        re = /.$/;
        w = w.replace(re,"");
      }
    }
    else if (re2.test(w)) {
      var fp = re2.exec(w);
      stem = fp[1];
      re2 = new RegExp(s_v);
      if (re2.test(stem)) {
        w = stem;
        re2 = /(at|bl|iz)$/;
        re3 = new RegExp("([^aeiouylsz])\\1$");
        re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
        if (re2.test(w))
          w = w + "e";
        else if (re3.test(w)) {
          re = /.$/;
          w = w.replace(re,"");
        }
        else if (re4.test(w))
          w = w + "e";
      }
    }

    // Step 1c
    re = /^(.+?)y$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      re = new RegExp(s_v);
      if (re.test(stem))
        w = stem + "i";
    }

    // Step 2
    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      suffix = fp[2];
      re = new RegExp(mgr0);
      if (re.test(stem))
        w = stem + step2list[suffix];
    }

    // Step 3
    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      suffix = fp[2];
      re = new RegExp(mgr0);
      if (re.test(stem))
        w = stem + step3list[suffix];
    }

    // Step 4
    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
    re2 = /^(.+?)(s|t)(ion)$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      re = new RegExp(mgr1);
      if (re.test(stem))
        w = stem;
    }
    else if (re2.test(w)) {
      var fp = re2.exec(w);
      stem = fp[1] + fp[2];
      re2 = new RegExp(mgr1);
      if (re2.test(stem))
        w = stem;
    }

    // Step 5
    re = /^(.+?)e$/;
    if (re.test(w)) {
      var fp = re.exec(w);
      stem = fp[1];
      re = new RegExp(mgr1);
      re2 = new RegExp(meq1);
      re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
        w = stem;
    }
    re = /ll$/;
    re2 = new RegExp(mgr1);
    if (re.test(w) && re2.test(w)) {
      re = /.$/;
      w = w.replace(re,"");
    }

    // and turn initial Y back to y
    if (firstch == "y")
      w = firstch.toLowerCase() + w.substr(1);
    return w;
  }
}


const extract_tokens_from_query = (query) => {
  const tokens = new Set();

  var inQuote = true
  var nextNegated = false

  const add_token = (tok,negated) => {
    if (tok.startsWith('!') || tok.startsWith('-'))
    {
      if (tok.length <= 1) return
      
      if (negated)
        tokens.add(tok.substr(1))
      else
        tokens.add('-' + tok.substr(1))
    }
    else 
    {
      if (tok.length < 1) return

      if (negated)
        tokens.add('-' + tok)
      else
        tokens.add(tok)
    }
  }

  query.split('"').forEach((quoteq) => {
    inQuote = !inQuote

    if (inQuote)
    {
      extract_tokens_from_query(quoteq).forEach((tok) => {
        add_token(tok,nextNegated)
      })
      nextNegated = false
    }
    else
    {
      quoteq.trim().split(/\s+/gi).forEach((tok) => {
        if (tok === "-" || tok === "!"){
          nextNegated = true
        }
        else {
          add_token(tok,nextNegated)
          nextNegated = false
        }
      })
    }
  })

  return tokens
}


var splitQuery = (query) => {
  // Remove scope arg
  const spl = query.split(':',2)
  if (spl.length > 1)
    return extract_tokens_from_query(spl[1].trim())
  else
    return extract_tokens_from_query(query)
}

const _displayNextItemFiltered = (
  results,
  resultCount,
  searchTerms,
  acceptor
) => {
  // results left, load the summary and display it
  // this is intended to be dynamic (don't sub resultsCount)
  if (results.length) {
    do 
      var nextItem = results.pop()
    while(!acceptor(nextItem));
  
    _displayItem(nextItem, searchTerms);
    setTimeout(
      () => _displayNextItemFiltered(results, resultCount+1, searchTerms,acceptor),
      5
    );
  }
  // search finished, update title and status message
  else _finishSearch(resultCount);
};

var generateScopeAcceptor = (query) => {
  query = query.replaceAll('"','')
  const spl = query.split(':',2)
  if (spl.length == 1)
    return [query,(_item) => { return true }]

  var keywordToFolderMap = {
    "over" : "aria_overview",
    "overview" : "aria_overview",

    "release" : "release_depr",
    "depr" : "release_depr",

    "theory" : "theory",

    "sim" : "simulation_setup",
    "setup" : "simulation_setup",

    "tutorials" : "tutorials",
    "tut" : "tutorials",

    "examples" : "examples",
    "ex" : "examples",

    "trouble" : "running_troubleshooting",
    "running" : "running_troubleshooting",

    "command_summary" : "command_summary",
    "command_ref" : "command_summary",
    "cmd" : "command_summary",
    "ref" : "command_summary",
  }

  var inclusive = new Set()
  var exclusive = new Set()

  var mapNameToFolder = (key) => {
    key = key.toLowerCase()
    if (key in keywordToFolderMap){
      return keywordToFolderMap[key]
    }
    else {
      return key
    }
  }

  extract_tokens_from_query(spl[0].trim()).forEach((comp) => {
    if (comp.startsWith('-'))
      exclusive.add(mapNameToFolder(comp.substr(1)))
    else
      inclusive.add(mapNameToFolder(comp))
  })
  
  const hasExclusive = exclusive.size > 0
  const hasInclusive = inclusive.size > 0

  if (!hasExclusive && !hasInclusive)
    return [spl[1].trim(),(_item) => { return true }]

  const exclusiveRe = new RegExp(
    hasExclusive ? ('^(' + [...exclusive].join('|') + ')/') : '.','i')

  const inclusiveRe = new RegExp(
    hasInclusive ? ('^(' + [...inclusive].join('|') + ')/') : '.','i')
  
  return [spl[1].trim(),(item) => {
    if (hasExclusive && exclusiveRe.test(item[5]))
    {
      return false
    }
    else if (hasInclusive && inclusiveRe.test(item[5]))
    {
      return true
    }

    // If an inclusive set is specified and you're not in it, exclude
    return !hasInclusive   
  }]
}
