text: /*
      This file is part of web3.js.
  
      web3.js is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.
  
      web3.js is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.
  
      You should have received a copy of the GNU Lesser General Public License
      along with web3.js.  If not, see <http://www.gnu.org/licenses/>.
  */
  /** 
   * @file iban.js
   * @author Marek Kotewicz <marek@ethdev.com>
   * @date 2015
   */
  
  var BigNumber = require('bignumber.js');
  
  var padLeft = function (string, bytes) {
      var result = string;
      while (result.length < bytes * 2) {
          result = '0' + result;
      }
      return result;
  };
  
  /**
   * Prepare an IBAN for mod 97 computation by moving the first 4 chars to the end and transforming the letters to
   * numbers (A = 10, B = 11, ..., Z = 35), as specified in ISO13616.
   *
   * @method iso13616Prepare
   * @param {String} iban the IBAN
   * @returns {String} the prepared IBAN
   */
  var iso13616Prepare = function (iban) {
      var A = 'A'.charCodeAt(0);
      var Z = 'Z'.charCodeAt(0);
  
      iban = iban.toUpperCase();
      iban = iban.substr(4) + iban.substr(0,4);
  
      return iban.split('').map(function(n){
          var code = n.charCodeAt(0);
          if (code >= A && code <= Z){
              // A = 10, B = 11, ... Z = 35
              return code - A + 10;
          } else {
              return n;
          }
      }).join('');
  };
  
  /**
   * Calculates the MOD 97 10 of the passed IBAN as specified in ISO7064.
   *
   * @method mod9710
   * @param {String} iban
   * @returns {Number}
   */
  var mod9710 = function (iban) {
      var remainder = iban,
          block;
  
      while (remainder.length > 2){
          block = remainder.slice(0, 9);
          remainder = parseInt(block, 10) % 97 + remainder.slice(block.length);
      }
  
      return parseInt(remainder, 10) % 97;
  };
  
  /**
   * This prototype should be used to create iban object from iban correct string
   *
   * @param {String} iban
   */
  var Iban = function (iban) {
      this._iban = iban;
  };
  
  /**
   * This method should be used to create iban object from ethereum address
   *
   * @method fromAddress
   * @param {String} address
   * @return {Iban} the IBAN object
   */
  Iban.fromAddress = function (address) {
      var asBn = new BigNumber(address, 16);
      var base36 = asBn.toString(36);
      var padded = padLeft(base36, 15);
      return Iban.fromBban(padded.toUpperCase());
  };
  
  /**
   * Convert the passed BBAN to an IBAN for this country specification.
   * Please note that <i>"generation of the IBAN shall be the exclusive responsibility of the bank/branch servicing the account"</i>.
   * This method implements the preferred algorithm described in http://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits
   *
   * @method fromBban
   * @param {String} bban the BBAN to convert to IBAN
   * @returns {Iban} the IBAN object
   */
  Iban.fromBban = function (bban) {
      var countryCode = 'XE';
  
      var remainder = mod9710(iso13616Prepare(countryCode + '00' + bban));
      var checkDigit = ('0' + (98 - remainder)).slice(-2);
  
      return new Iban(countryCode + checkDigit + bban);
  };
  
  /**
   * Should be used to create IBAN object for given institution and identifier
   *
   * @method createIndirect
   * @param {Object} options, required options are "institution" and "identifier"
   * @return {Iban} the IBAN object
   */
  Iban.createIndirect = function (options) {
      return Iban.fromBban('WON' + options.institution + options.identifier);
  };
  
  /**
   * Thos method should be used to check if given string is valid iban object
   *
   * @method isValid
   * @param {String} iban string
   * @return {Boolean} true if it is valid IBAN
   */
  Iban.isValid = function (iban) {
      var i = new Iban(iban);
      return i.isValid();
  };
  
  /**
   * Should be called to check if iban is correct
   *
   * @method isValid
   * @returns {Boolean} true if it is, otherwise false
   */
  Iban.prototype.isValid = function () {
      return /^XE[0-9]{2}(WON[0-9A-Z]{13}|[0-9A-Z]{30,31})$/.test(this._iban) &&
          mod9710(iso13616Prepare(this._iban)) === 1;
  };
  
  /**
   * Should be called to check if iban number is direct
   *
   * @method isDirect
   * @returns {Boolean} true if it is, otherwise false
   */
  Iban.prototype.isDirect = function () {
      return this._iban.length === 34 || this._iban.length === 35;
  };
  
  /**
   * Should be called to check if iban number if indirect
   *
   * @method isIndirect
   * @returns {Boolean} true if it is, otherwise false
   */
  Iban.prototype.isIndirect = function () {
      return this._iban.length === 20;
  };
  
  /**
   * Should be called to get iban checksum
   * Uses the mod-97-10 checksumming protocol (ISO/IEC 7064:2003)
   *
   * @method checksum
   * @returns {String} checksum
   */
  Iban.prototype.checksum = function () {
      return this._iban.substr(2, 2);
  };
  
  /**
   * Should be called to get institution identifier
   * eg. XREG
   *
   * @method institution
   * @returns {String} institution identifier
   */
  Iban.prototype.institution = function () {
      return this.isIndirect() ? this._iban.substr(7, 4) : '';
  };
  
  /**
   * Should be called to get client identifier within institution
   * eg. GAVOFYORK
   *
   * @method client
   * @returns {String} client identifier
   */
  Iban.prototype.client = function () {
      return this.isIndirect() ? this._iban.substr(11) : '';
  };
  
  /**
   * Should be called to get client direct address
   *
   * @method address
   * @returns {String} client direct address
   */
  Iban.prototype.address = function () {
      if (this.isDirect()) {
          var base36 = this._iban.substr(4);
          var asBn = new BigNumber(base36, 36);
          return padLeft(asBn.toString(16), 20);
      } 
  
      return '';
  };
  
  Iban.prototype.toString = function () {
      return this._iban;
  };
  
  module.exports = Iban;
  
  