﻿var postalCodeValidators = {
    belgium: /^\s?\d{4}\s?$/,
    netherlands: /^\s?[1-9][0-9]{3}\s?[A-Z]{2}?$/i,
    luxembourg: /\s?\d{4}\s?/,
    france: /^\s?\d{5}\s?$/
};

var EBCDIC = {
  '0': '0',
  '1': '1', 'a': '1', 'j': '1',
  '2': '2', 'b': '2', 'k': '2', 's': '2',
  '3': '3', 'c': '3', 'l': '3', 't': '3',
  '4': '4', 'd': '4', 'm': '4', 'u': '4',
  '5': '5', 'e': '5', 'n': '5', 'v': '5',
  '6': '6', 'f': '6', 'o': '6', 'w': '6',
  '7': '7', 'g': '7', 'p': '7', 'x': '7',
  '8': '8', 'h': '8', 'q': '8', 'y': '8',
  '9': '9', 'i': '9', 'r': '9', 'z': '9'
};

var bankAccountValidators = {
    belgium: function(value) {
    
        if (/^\d{3}-\d{7}-\d{2}$/.test(value)) {
        
            var xy = parseInt(value.substr(0, 3) + value.substr(4, 7), 10);
            var z = parseInt(value.substr(12), 10);
        
            return xy % 97 == z;
        }
        
        return false;
    },
    
    netherlands: function(value, bic) {

        if (/^(0?\d{1,6}\d\d)$/.test(value)) {
            return true;
        }
        
        if (/^(\d{6}\d{3})$/.test(value)) {
        
            var xy = value.substr(0, 6) + value.substr(6, 3);
            var z = 0;
            for (var i = 9; i > 0; i--) {
                z += i * parseInt(xy.charAt(9-i));
            }
            return z % 11 == 0;
        }
        
        return false;
    },
    
    luxembourg: function(value) {
        
        if (/^\d{3}-\d{8}-\d{2}$/.test(value)) {
        
            var xy = parseInt(value.substr(0, 3) + value.substr(4, 8), 10);
            var z = parseInt(value.substr(13), 10);
        
            return xy % 97 == z;
        }
        
        return false;
    },

    france: function(value) {

        if (value == null) return false;

        var match = value.match(/^(\d{5})-(\d{5})-([A-Za-z0-9]{3,11})-(\d{2})$/);
        if (match) {

          var xy = match[1] + match[2];
          var z = match[3];
          var r = match[4];

          z2 = '';
          for (i = 0; i < 11; i++) {
            if (i >= z.length) {
              z2 = '0' + z2;
            } else {
              var c = z.charAt(i).toLowerCase();
              z2 += EBCDIC[c];
            }
          }

          return modulo(xy + z2 + r, 97) == 0;

        } else if (/^\d{5}-\d{4}$/.test(value)) {

          var x = value.substr(0, 5) + value.substr(6, 4);
          var t = 0;
          var m = 1;
          for (i = 0; i < 9; i++) {
            var xi = parseInt(x.charAt(i)) * m;

            while (xi > 9) {
              xi = (xi % 10) + Math.floor(xi / 10);
            }

            t += xi;

            m = m == 1 ? 2 : 1;

          }

          return t % 10 == 0;
        }

        return false;
    }
}

function modulo( aNumStr, aDiv)
{
  var tmp = "";
  var  l, r;
  var i;

  for ( i=0; i<aNumStr.length ; i++)
      {
        tmp += aNumStr.charAt( i);

        r = tmp % aDiv;
        tmp = r.toString( 10);
      }
  return tmp / 1;
}

function luhn(value)
{
    var sum = 0;
    for (var i = 0; i < value.length; i++ )
    {
        sum += parseInt(value.charAt(i));
    }
    
    for (var l = value.length - 1; l >= 0; l -= 2)
    {
        sum += [0,1,2,3,4,-4,-3,-2,-1,0][parseInt(value.charAt(l))];
    }
    
    var mod10 = sum % 10;
    return mod10 == 0 ? 0 : (10 - mod10);
}
 
$.validator.addMethod("postal", function(postalCode, element, params) {
    var country = $(params).val().toLowerCase();
    var postalFormat = postalCodeValidators[country];
    if (postalFormat == null) {
        return true;
    }

    return this.optional(element) == true || postalFormat.test(postalCode);
});

$.validator.addMethod("phone", function(phoneNumber, element) {
    phoneNumber = phoneNumber.replace(/[-+\\/() ]+/g, "");
    return this.optional(element) == true || /^\d{4,}$/.test(phoneNumber);
});

$.validator.addMethod("bic", function(bic, element) {
    return this.optional(element) == true || /^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$/i.test(bic);
});

$.validator.addMethod("bankaccount", function(bankAccount, element, params) {

    bankAccount = bankAccount.replace(/_+$/, '');
    
    var countryId = params[0];
    var country = $(countryId).val().toLowerCase();
    
    var bicId = params[1];
    var bic = $(bicId).val();
    
    var bankAccountTest = bankAccountValidators[country];
    if (bankAccountTest == null) {
        return true;
    }

    return this.optional(element) == true || bankAccountTest(bankAccount, bic);
});

$.validator.addMethod("imei", function(imei, element) {
    imei = imei.replace(/[ .-]+/g, '');
    
    var luhnCheckPassed = true;
    if (imei.length == 15) {
        var realImei = imei.substring(0, imei.length-1);
        luhnCheckPassed = luhn(realImei) == imei.charAt(imei.length-1);
    }
    
    return this.optional(element) == true || (/^[0-9]{15}$/.test(imei) && luhnCheckPassed);
});

