/*jslint browser: true, regexp: true, unparam: true */
/*global jQuery: true, module, require */

/*
 * jQuery Password Strength plugin for Twitter Bootstrap
 *
 * Copyright (c) 2008-2013 Tane Piper
 * Copyright (c) 2013 Alejandro Blanco
 * Dual licensed under the MIT and GPL licenses.
 */

var rulesEngine = {};

try {
  if (!jQuery && module && module.exports) {
    var jQuery = require_once("jquery"),
      jsdom = require_once("jsdom").jsdom;
    jQuery = jQuery(jsdom().defaultView);
  }
} catch (ignore) {}

(function ($, rulesEngine) {
  "use strict";
  var validation = {};

  rulesEngine.forbiddenSequences = ["0123456789", "abcdefghijklmnopqrstuvwxyz", "qwertyuiop", "asdfghjkl", "zxcvbnm", "!@#$%^&*()_+"];

  validation.wordNotEmail = function (options, word, score) {
    if (word.match(/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i)) {
      return score;
    }
    return 0;
  };

  validation.wordLength = function (options, word, score) {
    var wordlen = word.length,
      lenScore = Math.pow(wordlen, options.rules.raisePower);
    if (wordlen < options.common.minChar) {
      lenScore = lenScore + score;
    }
    return lenScore;
  };

  validation.wordSimilarToUsername = function (options, word, score) {
    var username = $(options.common.usernameField).val();
    if (username && word.toLowerCase().match(username.replace(/[\-\[\]\/\{\}\(\)\*\+\=\?\:\.\\\^\$\|\!\,]/g, "\\$&").toLowerCase())) {
      return score;
    }
    return 0;
  };

  validation.wordTwoCharacterClasses = function (options, word, score) {
    if (word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) || (word.match(/([a-zA-Z])/) && word.match(/([0-9])/)) || (word.match(/(.[!,@,#,$,%,\^,&,*,?,_,~])/) && word.match(/[a-zA-Z0-9_]/))) {
      return score;
    }
    return 0;
  };

  validation.wordRepetitions = function (options, word, score) {
    if (word.match(/(.)\1\1/)) {
      return score;
    }
    return 0;
  };

  validation.wordSequences = function (options, word, score) {
    var found = false,
      j;
    if (word.length > 2) {
      $.each(rulesEngine.forbiddenSequences, function (idx, seq) {
        if (found) {
          return;
        }
        var sequences = [seq, seq.split("").reverse().join("")];
        $.each(sequences, function (idx, sequence) {
          for (j = 0; j < word.length - 2; j += 1) {
            // iterate the word trough a sliding window of size 3:
            if (sequence.indexOf(word.toLowerCase().substring(j, j + 3)) > -1) {
              found = true;
            }
          }
        });
      });
      if (found) {
        return score;
      }
    }
    return 0;
  };

  validation.wordLowercase = function (options, word, score) {
    return word.match(/[a-z]/) && score;
  };

  validation.wordUppercase = function (options, word, score) {
    return word.match(/[A-Z]/) && score;
  };

  validation.wordOneNumber = function (options, word, score) {
    return word.match(/\d+/) && score;
  };

  validation.wordThreeNumbers = function (options, word, score) {
    return word.match(/(.*[0-9].*[0-9].*[0-9])/) && score;
  };

  validation.wordOneSpecialChar = function (options, word, score) {
    return word.match(/[!,@,#,$,%,\^,&,*,?,_,~]/) && score;
  };

  validation.wordTwoSpecialChar = function (options, word, score) {
    return word.match(/(.*[!,@,#,$,%,\^,&,*,?,_,~].*[!,@,#,$,%,\^,&,*,?,_,~])/) && score;
  };

  validation.wordUpperLowerCombo = function (options, word, score) {
    return word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) && score;
  };

  validation.wordLetterNumberCombo = function (options, word, score) {
    return word.match(/([a-zA-Z])/) && word.match(/([0-9])/) && score;
  };

  validation.wordLetterNumberCharCombo = function (options, word, score) {
    return word.match(/([a-zA-Z0-9].*[!,@,#,$,%,\^,&,*,?,_,~])|([!,@,#,$,%,\^,&,*,?,_,~].*[a-zA-Z0-9])/) && score;
  };

  rulesEngine.validation = validation;

  rulesEngine.executeRules = function (options, word) {
    var totalScore = 0;

    $.each(options.rules.activated, function (rule, active) {
      if (active) {
        var score = options.rules.scores[rule],
          funct = rulesEngine.validation[rule],
          result,
          errorMessage;

        if (!$.isFunction(funct)) {
          funct = options.rules.extra[rule];
        }

        if ($.isFunction(funct)) {
          result = funct(options, word, score);
          if (result) {
            totalScore += result;
          }
          if (result < 0 || (!$.isNumeric(result) && !result)) {
            errorMessage = options.ui.spanError(options, rule);
            if (errorMessage.length > 0) {
              options.instances.errors.push(errorMessage);
            }
          }
        }
      }
    });

    if ($.isFunction(options.common.onScore)) {
      totalScore = options.common.onScore(options, word, totalScore);
    }

    return totalScore;
  };
})(jQuery, rulesEngine);

try {
  if (module && module.exports) {
    module.exports = rulesEngine;
  }
} catch (ignore) {}
