'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.isAcceptable = isAcceptable;
exports.countOccurances = countOccurances;
exports.generateCandidateKeywordScores = generateCandidateKeywordScores;
exports.separateWords = separateWords;
exports.calculateWordScores = calculateWordScores;
exports.generateCandidateKeywords = generateCandidateKeywords;
exports.buildStopWordRegex = buildStopWordRegex;
exports.splitSentences = splitSentences;
exports.loadStopWords = loadStopWords;
exports.default = rake;

var _lodash = require('lodash');

var stopwords = require('./stopwords');

function isNumber(str) {
  return (/\d/.test(str)
  );
}

// TODO: smaller functions should be extracted from this
function isAcceptable(phrase, minCharLength, maxWordsLength) {
  // a phrase must have a min length in characters
  if (phrase < minCharLength) {
    return false;
  }
  // a phrase must have a max number of words
  var words = phrase.split(' ');
  if (words.length > maxWordsLength) {
    return false;
  }

  var digits = 0;
  var alpha = 0;
  //is there a better way to do this?
  for (var i = 0; i < phrase.length; i++) {
    if (/\d/.test(phrase[i])) digits += 1;
    if (/[a-zA-Z]/.test(phrase[i])) alpha += 1;
  }

  // a phrase must have at least one alpha character
  if (alpha == 0) {
    return false;
  }

  // a phrase must have more alpha than digits characters
  if (digits > alpha) {
    return false;
  }

  return true;
}

function countOccurances(haystack, needle) {
  return haystack.reduce(function (n, value) {
    return n + (value === needle);
  }, 0);
}

function generateCandidateKeywordScores(phraseList, wordScore) {
  var minKeywordFrequency = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;


  var keywordCandidates = {};

  phraseList.forEach(function (phrase) {
    if (minKeywordFrequency > 1) {
      if (countOccurances(phraseList, phrase) < minKeywordFrequency) {
        return;
      }
    }
    phrase in keywordCandidates || (keywordCandidates[phrase] = 0);
    var wordList = separateWords(phrase, 0);
    var candidateScore = 0;
    wordList.forEach(function (word) {
      candidateScore += wordScore[word];
      keywordCandidates[phrase] = candidateScore;
    });
  });
  return keywordCandidates;
}

function separateWords(text, minWordReturnSize) {
  var wordDelimiters = /[^a-zA-Z0-9_\+\-/]/;
  var words = [];
  text.split(wordDelimiters).forEach(function (singleWord) {
    var currentWord = singleWord.trim().toLowerCase();
    //leave numbers in phrase, but don't count as words, since they tend to invalidate scores of their phrases
    if (currentWord.length > minWordReturnSize && currentWord != '' && !isNumber(currentWord)) {
      words.push(currentWord);
    }
  });
  return words;
}

function calculateWordScores(phraseList) {
  var wordFrequency = {};
  var wordDegree = {};
  phraseList.forEach(function (phrase) {
    var wordList = separateWords(phrase, 0);
    var wordListLength = wordList.length;
    var wordListDegree = wordListLength - 1;
    wordList.forEach(function (word) {
      word in wordFrequency || (wordFrequency[word] = 0);
      wordFrequency[word] += 1;
      word in wordDegree || (wordDegree[word] = 0);
      wordDegree[word] += wordListDegree;
    });
  });

  Object.keys(wordFrequency).forEach(function (item) {
    wordDegree[item] = wordDegree[item] + wordFrequency[item];
  });

  // Calculate Word scores = deg(w)/frew(w)
  var wordScore = {};
  Object.keys(wordFrequency).forEach(function (item) {
    item in wordScore || (wordScore[item] = 0);
    wordScore[item] = wordDegree[item] / (wordFrequency[item] * 1.0);
  });

  return wordScore;
}

function generateCandidateKeywords(sentenceList, stopWordPattern) {
  var minCharLength = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
  var maxWordsLength = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5;

  var phraseList = [];
  sentenceList.forEach(function (sentence) {
    var tmp = stopWordPattern[Symbol.replace](sentence, '|');
    var phrases = tmp.split("|");
    phrases.forEach(function (ph) {
      var phrase = ph.trim().toLowerCase();

      if (phrase != "" && isAcceptable(phrase, minCharLength, maxWordsLength)) {
        phraseList.push(phrase);
      } else {}
    });
  });
  return phraseList;
}

function buildStopWordRegex(path) {
  var stopWordList = loadStopWords(path);
  var stopWordRegexList = [];
  stopWordList.forEach(function (word) {
    if (/\w+/.test(word)) {
      // match only stop words surrounded by word boundaries (\b)
      var wordRegex = '\\b' + word + '\\b';
      stopWordRegexList.push(wordRegex);
    }
  });
  var stopWordPattern = new RegExp(stopWordRegexList.join('|'), 'ig');
  return stopWordPattern;
}

function splitSentences(text) {
  var sentenceDelimiters = /[\[\]\n.!?,;:\t\\-\\"\\(\\)\\\'\u2019\u2013]/;
  return text.split(sentenceDelimiters);
}

function loadStopWords(path) {
  var contents = stopwords.stopwords;

  //TODO: we are assuming one word per line
  return contents;
}

function rake(text, stopWordsPath) {
  var minCharLength = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 3;
  var maxWordsLength = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5;
  var minKeywordFrequency = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;

  var stopWordPattern = buildStopWordRegex(stopWordsPath);
  var sentenceList = splitSentences(text);
  var phraseList = generateCandidateKeywords(sentenceList, stopWordPattern, minCharLength, maxWordsLength);
  var wordScores = calculateWordScores(phraseList);
  var keywordCandidates = generateCandidateKeywordScores(phraseList, wordScores, minKeywordFrequency);
  var sortedKeywords = (0, _lodash.fromPairs)((0, _lodash.sortBy)((0, _lodash.toPairs)(keywordCandidates), function (pair) {
    return pair[1];
  }).reverse());
  return sortedKeywords;
}